Вопрос по python, stdin, buffering, linux – Python в режиме raw stdin print добавляет пробелы

7

Мне нужно было переключить стандартный ввод в небуферизованный режим в 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)

Ваш Ответ

3   ответа
7

,'приготовленные», а также 'CBREAK» режимы. И эти режимы являются режимами драйвера терминала уровня ядра, а не режимами кода вашего приложения или стандартной библиотеки или чего-либо еще в пользовательском пространстве. Это старый способ Unix сослаться на них. Posix заменил их гораздо более детализированным набором атрибутов, хотя атрибуты Posix обычно переворачиваются вместе с вспомогательными функциями таким образом, что имитирует старые 'сырой ','приготовленные» а также '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

В 'сырые» В этом режиме обработка не выполняется ни на входе, ни на выходе. Никакой специальной обработки символов, никакого эха, никакого преобразования\n в\r\n, нет обработки для Control-Z, ничего. Это'до программы, которая переводит терминал в режим raw, чтобы сделать все это.

Теперь вы устанавливаете атрибуты дляsys.stdin так что вы можете подумать, что это не должнот влияетsys.stdout, Но на самом деле оба ваших файловых дескриптора приводят к одинаковомупример' терминального драйвера. И это's настройки для драйвера терминала, которые определяют, что происходит. Так что это нене имеет значения, если вы измените эти настройки через,sys.stdinsys.stdout, или дажеsys.stderrвсе они изменяют один и тот же базовый экземпляр драйвера терминала и влияют на все остальные.

Это, конечно, не относится к дескрипторам файлов, которые были перенаправлены оболочкой до запуска вашей программы.

В качестве примечания вы можете использоватьstty -a в командной строке, чтобы увидеть полное чтение всех этих флагов (включая то, какие управляющие символы приводят к тому, какие сигналы в режимах приготовления и разбивания).

@TheDavidFactor - одна вещь, которую я пропустил, это то, что, очевидно, posix в значительной степени покончил с дискретными режимами на уровне драйвера и вместо этого превратил режимы в более тонкий набор зерен, состоящий в основном из независимых флагов. Omnifarious
Это гораздо лучший и более подробный ответ, чем мой +1 TheDavidFactor
5

вы только переводите строки, но не возвращаете карету. Измените свою печать на

print("ASD", end="\r\n")
Пока это кажется правильным; Я был под впечатлением, я никогда не должен вставлять\r вручную под Linux. Спасибо K.Steff
@halex Не могли бы вы объяснить, почему именно это необходимо в режиме raw, а не при обычной печати? Благодарю. Stefan
7

Google привел меня сюда, когда я искал ответ на этот же вопрос. Подсказка, которую поделил Халекс «Возврат кареты», помогла мне найти правду. Я нашел свои ответы в посте о Крисес вики: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()

Похожие вопросы