Q:

Bash read command and stdin redirection

As I understand the bash documentation both | and < redirect stdin. So, cmd | foo and foo < <(cmd) should be more or less equivalent. However, for the bash-internal read command this doesn't seem to be the case. E.g., if I enter
a=""; b=""; read a b < <(echo a b); echo $a $b

it prints out a b, while 
a=""; b=""; echo a b | read a b; echo $a $b

prints out nothing. On the other hand, if I enter
a=""; b=""; cat < <(echo a b) >foo1

a=""; b=""; echo a b | cat > foo2

the files foo1 and foo2 are exactly the same. So my question is: what is the difference with both forms when the read command is involved (or in general)? They should see exactly the same redirected input. While the < <(...) form works, I find it pretty unreadable and would much prefer to use the pipe form.

A:

The act of pipelining executes read in a subshell, whereas process substitution does not. For most use cases, this isn't a problem, but in this instance you want to directly affect the shell (by manipulating variables). Because read has been invoked in a subshell, only the subshell is affected. As such, any actions that you might wish to perform on them will need to also be performed in the subshell; for example:
echo a b | { read a b ; echo "$a" "$b" ; }

