Search the FAQ Archives

3 - A - B - C - D - E - F - G - H - I - J - K - L - M
N - O - P - Q - R - S - T - U - V - W - X - Y - Z
faqs.org - Internet FAQ Archives

Unix - Frequently Asked Questions (3/7) [Frequent posting]
Section - Why doesn't redirecting a loop work as intended? (Bourne shell)

( Part1 - Part2 - Part3 - Part4 - Part5 - Part6 - Part7 - Single Page )
[ Usenet FAQs | Web FAQs | Documents | RFC Index | Business Photos and Profiles ]


Top Document: Unix - Frequently Asked Questions (3/7) [Frequent posting]
Previous Document: How can a process detect if it's running in the background?
Next Document: How do I run ... interactive programs from a shell script ... ?
See reader questions & answers on this topic! - Help others by sharing your knowledge

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.

User Contributions:

Comment about this article, ask questions, or add new information about this topic:

CAPTCHA




Top Document: Unix - Frequently Asked Questions (3/7) [Frequent posting]
Previous Document: How can a process detect if it's running in the background?
Next Document: How do I run ... interactive programs from a shell script ... ?

Part1 - Part2 - Part3 - Part4 - Part5 - Part6 - Part7 - Single Page

[ Usenet FAQs | Web FAQs | Documents | RFC Index ]

Send corrections/additions to the FAQ Maintainer:
tmatimar@isgtec.com (Ted Timar)





Last Update March 27 2014 @ 02:12 PM