Reading input while also piping a script via stdin

bash, shell

Solution

Instead of just running

read X

...instead replace it with...

read X </dev/tty || {
  X="some default because we can't read from the TTY here"
}

...if you want to read from the console. Of course, this only works if you have a `/dev/tty`, but if you wanted to do something robust, you wouldn't be piping from `curl` into a shell. :)

Another alternative, of course, is to pass in your value of `X` on the command line.

curl https://some.place/with-untrusted-code-only-idiots-will-run-without-reading \
  | bash -s "value of X here"

...and refer to `"$1"` in your script when you want `X`.

(By the way, I sure hope you're at least using SSL for this, rather than advising people to run code they download over plain HTTP with no out-of-band validation step. Lots of people do it, sure, but that's making sites they download from -- like `rvm.io` -- big targets. Big, easy-to-man-in-the-middle-or-DNS-hijack targets).

Problem

I have a simple Bash script: ``` #!/usr/bin/env bash read X echo "X=$X" ``` When I execute it with `./myscript.sh` it works. But when I execute it with `cat myscript.sh | bash` it actually puts `echo "X=$X"` into `$X`. So this script prints Hello World executed with `cat myscript.sh | bash`: ``` #!/usr/bin/env bash read X hello world echo "$X" ``` - What's the benefit of executing a script with `cat myscript.sh | bash`? Why doesn't do it the same things as if I execute it with `./myscript.sh`? - How can I avoid Bash to execute line by line but execute all lines after the STDIN reached the end?

Original source

Related problems