How to disable TTY echo in Python when STDIN is piped

Viewed 453

To use a command-line program with an interactive TTY, you just need to execute that program in a shell (of course, the program needs to do blocking I/O operations on STDIN/STDOUT). For example : python -i.

But you can also do this: cat - | python -i. This is useful to feed STDIN with a file first then with an interactive TTY. For example: cat prelude.py - | python -i. This way you get an interactive TTY after piping the whole content of the script into STDIN. I know there are other ways to load a script in the Python interactive shell, this is just an example.

I want to write a Python script that behave the same way. Here is my current testing script:

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()

Both python test.py and cat - | python test.py work but unlike python -i i have an echo of what's poured into STDIN.

How can I disable this echo ? The following code works with python test.py:

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

But with cat - | python test.py I get the following error:

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')

Is there a generic way to disable echo for STDIN wether it's piped or not ? Is there a specific way to disable echo for a piped STDIN and that I can use when sys.stdin.isatty() return False?

Thanks for your advice !

0 Answers
Related