Search code examples
bashpipewgetstdin

Using read -p in a bash script that was executed from pipe


I apologize in advance - I don't fully understand the ideas behind what I'm asking well enough to understand why it's not working (I don't know what I need to learn). I searched stack exchange for answers first - I found some information that seemed possibly relevant, but didn't explain the concepts well enough that I understood how to build a working solution. I've been scouring google but haven't found any information that describes exactly what's going on in such a way that I understand. Any direction to background concepts that may help me understand what's going on would be greatly appreciated.

Is it possible to get user input in a bash script that was executed from a pipe?

For example:

wget -q -O - http://myscript.sh | bash

And in the script:

read -p "Do some action (y/n): " __response
if [[ "$__response" =~ ^[Yy]$ ]]; then
   echo "Performing some action ..."
fi

As I understand it, this doesn't work because read attempts to read the input from stdin and the bash script is currently "executing through that pipe" (i'm sure there is a more technical accurate way to describe what is occurring, but i don't know how).

I found a solution that recommended using:

read -t 1 __response </dev/tty

However, this does not work either.

Any light shed on the concepts I need to understand to make this work, or explanations of why it is not working or solutions would be greatly appreciated.


Solution

  • The tty solution works. Test it with this code, for example:

    $ date | { read -p "Echo date? " r </dev/tty ; [ "$r" = "y" ] && cat || echo OK ; }
    Echo date? y
    Sat Apr 12 10:51:16 PDT 2014
    $ date | { read -p "Echo date? " r </dev/tty ; [ "$r" = "y" ] && cat || echo OK ; }
    Echo date? n
    OK
    

    The prompt from read appears on the terminal and read waits for a response before deciding to echo the date or not.

    What I wrote above differs from the line below in two key aspects:

    read -t 1 __response </dev/tty
    

    First, the option -t 1 gives read a timeout of one second. Secondly, this command does not provide a prompt. The combination of these two probably means that, even though read was briefly asking for input, you didn't know it.