UNIX FAQ Version 2.1 92/12/04 -- Question 3.8

UNIX FAQ Version 2.1 92/12/04 -- Question 3.8

Why doesn't redirecting a loop work as intended? (Bourne shell)

Take the following example: foo=bar while read line do # do something with $line foo=bletch done < /etc/passwd echo "foo is now: $foo" Despite the assignment ``foo=bletch'' this will print ``foo is now: bar'' in many implementations of the Bourne shell. Why? Because of the following, often undocumented, feature of historic Bourne shells: redirecting a control structure (such as a loop, or an ``if'' statement) causes a subshell to be created, in which the structure is executed; variables set in that subshell (like the ``foo=bletch'' assignment) don't affect the current shell, of course. The POSIX 1003.2 Shell and Tools Interface standardization committee forbids the behaviour described above, i.e. in P1003.2 conformant Bourne shells the example will print ``foo is now: bletch''. In historic (and P1003.2 conformant) implementations you can use the following `trick' to get around the redirection problem: foo=bar # make file descriptor 9 a duplicate of file descriptor 0 (stdin); # then connect stdin to /etc/passwd; the original stdin is now # `remembered' in file descriptor 9; see dup(2) and sh(1) exec 9<&0 < /etc/passwd while read line do # do something with $line foo=bletch done # make stdin a duplicate of file descriptor 9, i.e. reconnect # it to the original stdin; then close file descriptor 9 exec 0<&9 9<&- echo "foo is now: $foo" This should always print ``foo is now: bletch''. Right, take the next example: foo=bar echo bletch | read foo echo "foo is now: $foo" This will print ``foo is now: bar'' in many implementations, ``foo is now: bletch'' in some others. Why? Generally each part of a pipeline is run in a different subshell; in some implementations though, the last command in the pipeline is made an exception: if it is a builtin command like ``read'', the current shell will execute it, else another subshell is created. POSIX 1003.2 allows both behaviours so portable scripts cannot depend on any of them.