Как отключить эхо TTY в Python, когда STDIN передается по конвейеру

Чтобы использовать программу командной строки с интерактивным TTY, вам просто нужно выполнить эту программу в оболочке (конечно, программа должна выполнять блокирующие операции ввода-вывода на STDIN / STDOUT). Например: python -i.

Но вы также можете сделать это: cat - | python -i. Это полезно для подачи в STDIN сначала файла, а затем интерактивного телетайпа. Например: cat prelude.py - | python -i. Таким образом, вы получите интерактивный TTY после, передающий все содержимое скрипта в STDIN. Я знаю, что есть и другие способы загрузить скрипт в интерактивную оболочку Python, это всего лишь пример.

Я хочу написать сценарий Python, который ведет себя таким же образом. Вот мой текущий сценарий тестирования:

import os
import sys
import threading

def main():
    thread_loop = True
    def thread_func():
        unbuf_fd = os.fdopen(sys.stdin.fileno(), 'rb', 0)
        sys.stdin.close()
        sys.stdin = unbuf_fd
        unbuf_fd = os.fdopen(sys.stdout.fileno(), 'wb', 0)
        sys.stdout.close()
        sys.stdout = unbuf_fd
        while(thread_loop):
            sys.stdout.write(sys.stdin.read(1))
        sys.stdout.write(b'Exiting...\n')
    def signal_func(sig, frame):
        global thread_loop
        print('You pressed Ctrl+C.')
        thread_loop = False
    forward_std = threading.Thread(target=thread_func, args=())
    forward_std.start()
    forward_std.join()

if __name__ == '__main__':
    main()

И python test.py, и cat - | python test.py работают, но, в отличие от python -i, у меня есть отголоски того, что залито в STDIN.

Как я могу отключить это эхо? Следующий код работает с python test.py:

fd = sys.stdin.fileno()
fd_attr = tty.tcgetattr(fd)
tty.setcbreak(fd)

Но с cat - | python test.py я получаю следующую ошибку:

Traceback (most recent call last):
  File "tata.py", line 33, in <module>
    main()
  File "tata.py", line 25, in main
    fd_attr = tty.tcgetattr(fd)
termios.error: (25, 'Inappropriate ioctl for device')

Есть ли общий способ отключить эхо для STDIN, подключено ли оно к каналу или нет? Есть ли конкретный способ отключить эхо для передаваемого по каналу STDIN и который я могу использовать, когда sys.stdin.isatty() вернет False?

Спасибо за ваш совет !

В случае cat - | python test.py сценарий Python не имеет дескриптора для TTY (только для канала от cat), поэтому будет сложно что-либо сделать с любым эхом клавиатуры. Единственный подход, который я могу придумать, - это рекурсивно пройти вверх по дереву процессов к каждому родительскому элементу, выяснить, является ли его стандартный ввод TTY от /proc/PID/fd/0, и, если да, открыть его и выполнить соответствующий ioctl. Но это уродливый хакер, который во многих ситуациях может пойти не так, как надо. Почему вы вообще хотите это сделать?

Thomas 31.03.2021 22:15

Обратите внимание, что cat foo.py - | python -i выводит нет содержимое foo.py, но выводит эхо ввода с клавиатуры. Вам не нужно делать ничего особенного, чтобы добиться такого поведения.

Thomas 31.03.2021 22:17

"Почему вы вообще хотите это сделать?" Ну, я хотел контролировать, какой символ из STDIN будет печататься в STDOUT, но я неправильно понимал связь между STDIN и TTY. Спасибо за вашу помощь.

Breune 04.04.2021 13:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
19
0

Другие вопросы по теме