I want to read data piped into my program and then take a user input using curses. I have the following code:
import curses
import sys
import select
def read_piped_data():
data = ""
while(sys.stdin in select.select([sys.stdin,],[],[],0.0)[0]):
x = sys.stdin.read(1)
if(len(x) == 0): break
data += x
sys.stdin = open("/dev/tty")
return (data if len(data) > 0 else None)
def main(stdscr):
data = read_piped_data()
if(data != None): do_something1(data)
curses.raw()
stdscr.keypad(True)
stdscr.timeout(0)
while(True):
ch = stdscr.getch()
if(ch == -1): continue
if(not do_something2(stdscr,ch)): break
curses.wrapper(main)
When I execute the above using:
$ python3 test.py
Everything works perfectly: do_something1() is not called but do_something2() is called whenever I press any key. But when I pipe something as:
$ ls | python3 test.py
My code fails: do_something1() is called and it correctly processes the piped-data but do_something2() is never called and my program is basically in an infinite loop, not registering any key-presses!
Keeping or removing the sys.stdin = open("/dev/tty") has no effect. In another stackoverflow answer I found this solution to make input() work (after reading from pipe). Although input() works after I reassign stdin, getch() doesn't.
Even if I do not read the piped data, just piping some command to my program is enough to mess with curses getch() preventing it from ever reading any key presses.
I am using curses with Python 3.8 on Ubuntu 20.04. How can I "reactivate" input in curses after having read from pipe?