General problem
I want to write a script that interacts with the user even though it is in the middle of a chain of pipes.
Concrete example
Concretely, it takes a file
or stdin
, displays lines (with line numbers), asks the user to input a selection or line numbers, and then prints the corresponding lines to stdout
. Let's call this script selector
. Then basically, I want to be able to do
grep abc foo | selector > myfile.tmp
If foo
contains
blabcbla
foo abc bar
quux
xyzzy abc
then selector
presents me (on the terminal, not in myfile.tmp
!) with options
1) blabcbla
2) foo abc bar
3) xyzzy abc
Select options:
after which I type in
2-3
and end up with
foo abc bar
xyzzy abc
as contents of myfile.tmp
.
I've got a selector script up and running, and basically it is working perfectly if I don't redirect input and output. So
selector foo
behaves like I want. However, when piping things together as in the above example, selector
prints the presented options to myfile.tmp
and tries to read a selection from the grepped input.
My approach
I've tried to use the -u
flag of read
, as in
exec 4< /proc/$PPID/fd/0
exec 4> /proc/$PPID/fd/1
nl $INPUT >4
read -u4 -p"Select options: "
but this doesn't do what I hoped it would.
Q: How do I get actual user interaction?
Best Answer
Using
/proc/$PPID/fd/0
is unreliable: the parent of theselector
process may not have the terminal as its input.There is a standard path that always refers to the current process's terminal:
/dev/tty
.or