1

Bash can run scripts from pipeline. A minimal example would be:

> echo "echo hello world" | bash
hello world

This is handy if you wants to run a script downloaded from curl or wget.

But apparently, you cannot use read in this kind of script execution. For example,

#!/bin/bash

echo 'input: '
read HELLO
echo hello: $HELLO

If you simply run the above script from a bash script file, you'd get to input the value of $HELLO. and the echo hello: $HELLO will print the result.

If you feed the script in the manner we talked about previously:

> echo "echo 'input: '; read HELLO; echo hello: $HELLO" | bash
input: 
hello:

You won't get the interaction at all. And $HELLO remains empty. I've also tried to add -i option in bash, and it didn't work.

Is there any way we can use read in the pipelined script? How? Or, if we can't, why?

1 Answers1

4

read will "interact" with the user via the stdin (where it will read stuff from) and stderr (where it will print its -p prompt, if any).

If the stdin is the script, read will get its stuff from it, causing it to skip a line:

$ echo '
read foo
what the -)(*$;?
echo "$foo"
' | bash
what the -)(*$;?

This is hardly a good practice, and will not work in all shells. Also notice that when piping scripts via stdin, bash will have to read them byte-by-byte.

In your example, your whole script was a single line, so the read builtin will just get EOF and not set any variables.

If you want read to always read from the controlling tty, then redirect it explicitly:

read var </dev/tty

This should be used sparingly, too. Nobody will appreciate you if they have to use expect(1) in order to instrument your script.