I want to write something like a terminal version of dmenu, which can be used to search for a file, and then pass the file's location to another program in the pipeline, like:
my_script | xargs vim # search for a file and open in vim
I tried to do it in python with output redirection, but it doesn't seem to work with curses.
import sys
import curses
prev_out = sys.stdout
print("1:", sys.stdout)
sys.stdout = open("/dev/tty", "w")
print("2:", sys.stdout)
window = curses.initscr()
window.addstr(1, 1, "testing")
window.getch()
curses.endwin()
sys.stdout = prev_out
print("3:", sys.stdout)
When I call it like this:
myscript > /dev/pts/1 # redirect output to another tty
print's behave how I'd expect them to (2 in original tty, 1 and 3 in the other one), but the curses UI is displayed in the /dev/pts/1.
So my question is, is there a way to redirect curses output back to /dev/tty, or is there a different way to display a text based GUI, which can be redirected by altering sys.stdout?
I achieved this behaviour by writing a short bash wrapper for my python script.
#!/bin/bash
# bash wrapper, that handles forking output between
# GUI and the output meant to go further down the pipe
# a pipe is created to catch the the wanted output
# date and username added in case of two scripts running at
# approximately the same time
fifo=/tmp/search_gui_pipe-$(whoami)-$(date +%H-%M-%S-%N)
[ ! -p "$fifo" ] && mkfifo $fifo
# python script is called in background, with stdin/out
# redirected to current tty, and location of the pipe file
# passed as an argument (also pass all args for parsing)
./search_gui.py "$fifo" $@ >/dev/tty </dev/tty &
# write the program output to stdout and remove the pipe file
cat "$fifo" && rm "$fifo"