简体   繁体   中英

How to read user input when script is piped to shell?

If I do the following

#!/bin/bash
echo aaa
read -i aaa
echo bbb
echo $aaa

and start it by cat test.sh | bash cat test.sh | bash then I get

aaa

without being asked for input.

Question

The script have to be started by cat test.sh | bash cat test.sh | bash to simulate wget -qO - url | bash wget -qO - url | bash , how can I ask the user to type input?

By running cat test.sh | bash cat test.sh | bash , you replace the stdin of the bash process (which normally is the terminal, thus, "the keyboard") with a pipe file descriptor connected to a cat process writing the contents of test.sh .

But while bash is reading from the pipe to execute the commands in your script, it also executes read -i aaa which reads from stdin as well, and may read the commands which where meant for bash.

That means we probably have undefined behaviour here, unless it is specified in what chunks bash reads its commands.

So, when piping a script to a shell, better not use any commands consuming input inside the script.

And why did the final echo $aaa obviously only print a newline, but not what read read? Because you didn't mean to say read -i aaa , but just read aaa .

It's not so usual to read a shell script from stdin anyway. Just execute as bash test.sh or use a shebang line .

the read builtin reads from stdin and in your scenario stdin is the redirected output from cat. When you are calling read it's just trying to read more from cat, not the keyboard.

Try one of the following options to read:

-e  readline is used to obtain the line.
or
-u FD   Read input from file descriptor FD.

In the second case i'm not sure what a sane value for FD might be (a keyboard or tty device in /dev/ ?)

I'm not even sure you can use read for this.

The script have to be started by cat test.sh | bash,

Why is that? cat will print your script on stdout rather than executing it.

Just execute your script as:

bash ./test.sh

UPDATE: Based on your comment:

This should also work:

bash <(cat "test.sh")

Use:

read -i aaa < /dev/tty

to read from the terminal, rather than the shell's standard input.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM