Ответ 1
Похоже, вы делаете только фид строки, но возврат каретки. Измените печать на
print("ASD", end="\r\n")
Мне нужно было переключить стандартный ввод на небуферизованный режим в Python, чтобы я мог читать отдельные символы. Мне удалось заставить его работать, но теперь стандартный вывод нарушен: как-то кажется после символа новой строки, выделяются некоторые пробельные символы, нуль в первой строке, 3 на втором, 6 на третьем и т.д., Как это
ASD
ASD
ASD
Операционная система - Ubuntu Linux 12.04, 64-разрядная версия, версия Python - 3.2.3.
Как я могу избавиться от этого поведения?
Ниже приведен код, который я использовал:
import sys
import tty
import termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
tty.setraw(sys.stdin)
for i in range(0, 10):
print("ASD")
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
Похоже, вы делаете только фид строки, но возврат каретки. Измените печать на
print("ASD", end="\r\n")
Google привел меня сюда, когда я искал ответ на этот же вопрос. Ключ, разделенный халексами без каретки, помог мне найти правду. Я нашел ответы в записи на Chris Wiki: https://utcc.utoronto.ca/~cks/space/blog/unix/CBreakAndRaw, которые заставляют меня читать источник tty.py здесь: https://hg.python.org/cpython/file/618ea5612e83/Lib/tty.py Это привело меня к выводу, что если цель состоит в том, чтобы читать одиночные символы, а не:
tty.setraw()
Использование:
tty.setcbreak()
Проблема, с которой вы сталкиваетесь, - это разница между режимами "raw", "cooked" и "cbreak". И эти режимы являются режимами драйвера терминала уровня ядра, а не режимами вашего кода приложения или стандартной библиотеки или чего-либо еще в пользовательском пространстве.
В приготовленном режиме сам драйвер терминала имеет встроенные функции редактирования строк. Он обрабатывает обратное пространство, стирание слов (в основном, обратное целое слово одновременно) и подобные вещи. Ничего сложного, как использование клавиш со стрелками или истории или что-то в этом роде. Очень примитивный. В этом режиме ваша программа никогда не видит ничего от терминала до тех пор, пока не будет отправлен символ конца строки (eol), а затем ваша программа получит целую строку, а окончание строки будет переведено в стандарт Unix \n
независимо от того, что терминал фактически делает. Кроме того, как часть этого, драйвер терминала повторяет введенные символы обратно на терминал, чтобы пользователь мог видеть, что они набирают.
В режиме "приготовленного" драйвер терминала уровня ядра также выполняет некоторый перевод вывода. И часть этого превращает \n
в \r\n
, если это необходимо.
Кроме того, в режиме "приготовленного" драйвер терминала обрабатывает специальные символы, такие как Control-C (отправляет SIGINT в группу процессов управления (транслируется CPython в исключение KeyboardInterrupt)) и Control-Z (отправляет SIGTSTP (например, SIGSTOP, но можно поймать) в группу процессов управления).
В режиме 'cbreak' редактирование строк больше не выполняется. Драйвер терминала дает каждому персонажу (или короткую последовательность символов, такую как escape-последовательность для клавиши со стрелкой), в программу немедленно. Эти символы не отображаются на экране, поэтому, если ваша программа не распечатает их, пользователь их не увидит. Драйвер терминала хотя и обрабатывает специальные символы, такие как Control-C и Control-Z, хотя он перестает обрабатывать символы редактирования строк, такие как backspace или символ стирания слов (обычно Control-W). Кроме того, некоторая обработка вывода все еще выполняется, поэтому драйвер превращает \n
в \r\n
.
В режиме "raw" обработка не выполняется ни на входе, ни на выходе. Никакой специальной обработки символов, без эха, без преобразования \n
в \r\n
, без обработки для Control-Z ничего. Это до программы, которая помещает терминал в необработанном режиме, чтобы сделать все это.
Теперь вы устанавливаете атрибуты для sys.stdin
, чтобы вы могли подумать, что это не должно влиять на sys.stdout
. Но, на самом деле, оба дескриптора файла приводят к тому же "экземпляру" драйвера терминала. И это настройки для драйвера терминала, которые определяют, что происходит. Поэтому неважно, измените ли вы эти параметры с помощью sys.stdin
, sys.stdout
или даже sys.stderr
, все измените один и тот же базовый экземпляр драйвера терминала, и они повлияют на все остальные.
Это, конечно, не относится к файловым дескрипторам, которые были перенаправлены оболочкой перед запуском вашей программы.