Subshells 2
In my experience, subshells were the most confusing aspect of Unix.
From Chapter 28 in The Linux Command Line:
YOU CAN’T PIPE READ
While the read command normally takes input from standard input, you cannot do this:
echo "foo" | read
We would expect this to work, but it does not. The command will appear to succeed, but the
REPLY
variable will always be empty. Why is this? The explanation has to do with the way the shell handles pipelines. In bash (and other shells such as sh), pipelines create subshells. These are copies of the shell and its environment that are used to execute the command in the pipeline. In our previous example,read
is executed in a subshell. Subshells in Unix-like systems create copies of the environment for the processes to use while they execute. When the processes finish, the copy of the environment is destroyed. This means that a subshell can never alter the environment of its parent process.read
assigns variables, which then become part of the environment. In the example above,read
assigns the value foo to the variableREPLY
in its subshell’s environment, but when the command exits, the subshell and its environment are destroyed, and the effect of the assignment is lost.Using here strings is one way to work around this behavior. Another method is discussed in Chapter 36.
That method is process substition.
Examples
Using herestrings
read <<< echo "foo"
echo $REPLY
Using process substition
Using process substitution
while read line; do echo \# $line; done < <(cat --help)
This doesn’t work
while read line; do echo \# $line; done < $(cat --help)
because it is a (here)string, not a file. So use <<<
to redirect it:
while read -r line; do echo \# $line; done <<< $(cat --help)
The following is another method (but it creates a file):
cat --help > cathelp
while read -r line; do echo \# $line; done < cathelp
rm cathelp
Redirection syntax
For more info on redirection syntax, see the this redirection cheatsheet.