bashinputpipeherestring

Why does the read command in bash work with a herestring but not with piped output?


I'm trying to understand how the bash read command works under the hood. Given that it expects its input to come from standard input, I was surprised to find out that piped input does not work as expected. E.g.

### Pipe scenario

echo "1 2 3" | read -r one two three
echo "one: $one, two: $two, three: $three"
# output:   'one: , two: , three:' 

### Herestring scenario

read -r one two three <<< "1 2 3"
echo "one: $one, two: $two, three: $three"
# output:   'one: 1, two: 2, three: 3'

Can someone explain in what fundamental way do the above two ways of providing input differ from each other (from the point of view of the read command)?



EDIT in response to comments:

I do not want to know "how to work around passing input via a pipe", like the linked questions in the comments. I know how to do that (e.g. I can use a herestring!).

My question is, what is the underlying mechanism that makes read behave differently in the two cases?


Solution

  • The read works, but you need to ask for the values in the same subshell:

    echo "1 2 3" | (read -r one two three && echo "one: $one, two: $two, three: $three")
    

    An alternative is

    read -r one two three < <( echo "1 2 3")