How can I pipe initial input into process which will then be interactive?
You don't need to write a new tool to forward stdin
- one has already been written (cat
):
(echo "initial command" && cat) | some_tool
This does have the downside of connecting a pipe to some_tool
, not a terminal.
How to pipe data to interactive bash script and pipe output to another command?
Thanks to 4ae1e1, I figured out how to do what I want - specifically, how to get my select_from_list
routine to work:
So now I can do something like this:
ls /tmp/ | select_from_list | xargs cat
to choose a file from /tmp
and cat it.
select_from_list
#!/bin/bash
prompt="Please select an item:"
options=()
if [ -z "$1" ]
then
# Get options from PIPE
input=$(cat /dev/stdin)
while read -r line; do
options+=("$line")
done <<< "$input"
else
# Get options from command line
for var in "$@"
do
options+=("$var")
done
fi
# Close stdin
0<&-
# open /dev/tty as stdin
exec 0</dev/tty
PS3="$prompt "
select opt in "${options[@]}" "Quit" ; do
if (( REPLY == 1 + ${#options[@]} )) ; then
exit
elif (( REPLY > 0 && REPLY <= ${#options[@]} )) ; then
break
else
echo "Invalid option. Try another one."
fi
done
echo $opt
How to pipe two inputs to the same command?
You can use process substitution:
convert <(cat file1.txt) <(cat file2.txt)
How do I accept piped input and then user-prompted input in a Python script?
I suspect you're out of luck, at least for any kind of cross-platform solution. Python uses sys.stdin
for raw_input()
, and if you invoke Python so that sys.stdin
is on the receiving end of a pipe, Python can't do anything to magically change sys.stdin
to the terminal when the piped input ends.
Here's a variant of the question with a Unix-specific workaround as the accepted answer. That cleverly worms around some (not all) of the problem by changing the way the program is invoked.
Sorry.
One way
This seems to work fine for Windows:
import sys
print len(sys.stdin.read()) # anything to consume piped input
sys.stdin = open("CON:", "r")
x = raw_input("sdfklj ")
That is, after reading the piped-in input, sys.stdin
is rebound to the special file CON:
(which is what Windows calls a DOS box) opened in read mode.
See your Unix docs for what to try there - perhaps /dev/tty1
? There are mounds of terminal control options you may need to fiddle with too, depending on platform specifics. That's why I said (at the start) that I think you're out of luck for any cross-platform solution. Python has no special support for terminal devices; i.e., you're on your own for that.
Interactive shell using standard input
Method 1: Get user input via stderr
The problem is stdin for the shell is the cat
process and, apparently, you would like the question the user. One way to do that is:
$ cat hoge.sh
#!/bin/sh
read yn <&2
echo "yn is $yn"
This tells read
to get its stdin from the stderr, not the cat
process. Since stderr has not been redirected, it is still the terminal
In operation, it looks like this:
$ cat hoge.sh | sh
y
yn is y
Method 2: Get user input directly from the terminal
$ cat hoge.sh
#!/bin/sh
read yn </dev/tty
echo "yn is $yn"
When done this way, the read
command will get its input from the terminal and any attempt at I/O redirection will be ignored. This can be an advantage or disadvantage depending on your requirements.
How do I push a string to stdin? Provide input via stdin on startup, then read stdin input interactively
This might work:
(echo "something"; cat -) | ./my_program
It creates a sub-shell where the first line of output comes from echo
and the rest comes from the standard input to cat
, which is the terminal (or the script's standard input, at any rate). I use the -
to emphasize that cat
is required to read from standard input — it is not simply that I've forgotten to specify "$@"
or something after the cat
command. Omitting the -
doesn't make an operational difference; it might make a comprehensibility difference.
Be aware that the input to my_program
is no longer a terminal but a pipe connected to the terminal, which can affect the behaviour of the program. The cat
process introduces delays, too.
Expect
If that doesn't do the job, then you probably need to use expect
instead. This is a general purpose tool for scripting interactions with other programs, and it uses pseudo-ttys (ptys) to make it appear as if a user at a terminal is communicating with the other program.
As anishsane notes, expect
has an interact
command that can be used to leave you with the user typing to the program after some fixed preamble.
Beware
Adapting this to your second scenario was not a comfortable experience:
(echo date; cat -) | bash -i
The -i
tells Bash it is an interactive shell. The date
worked, and I got a prompt after it, but I didn't get any more commands executed. Interrupt got me more prompts; pretty much everything else seemed to be ignored. That may be cat
doing too much buffering of its output.
I ended up killing that shell from another terminal window. I had better luck with:
(echo date; cat -) | bash
but there were no prompts from Bash. Be careful; make sure you know how to get out of trouble.
I/O Redirection Stunts
rici also pointed out that in this particular case, you could use:
{ { echo date; echo 'exec 0<&3-';} | bash -i; } 3<&0
That's rather clever because the trailing 3<&0
makes a copy of the original standard input (file descriptor 0) on descriptor 3, and then runs bash -i
with its input coming from two echo
statements. The first requests the date. The second re-redirects things so that the standard input now comes from file descriptor 3 (that's the 0<&3
part) — which is the original standard input, aka 'the terminal' — and closes file descriptor 3 too (that's the trailing -
; it is a Bash extension over POSIX shell I/O redirection).
Related Topics
Shell Script: Run Function from Script Over Ssh
Syntax Error in Shell Script With Process Substitution
./Configure: /Bin/Sh^M: Bad Interpreter
"Unable to Find Remote Helper For 'Https'" During Git Clone
What Is Rss and Vsz in Linux Memory Management
Adding a New Entry to the Path Variable in Zsh
How Many Socket Connections Possible
Bash While Read Loop Extremely Slow Compared to Cat, Why
What Does the Number in Parentheses Shown After Unix Command Names in Manpages Mean
"Failed to Load Platform Plugin "Xcb" " While Launching Qt5 App on Linux Without Qt Installed
Expanding a Bash Array Only Gives the First Element
Finding Which Process Was Killed by Linux Oom Killer
How to Find Out What All Symbols Are Exported from a Shared Object