problems with 'while read'

Nicole Delbecque & Paul Bijnens FFAAC09 at cc1.kuleuven.ac.be
Tue May 7 08:51:18 AEST 1991


In article <3635 at dagobert.informatik.uni-kiel.dbp.de>,
wib at informatik.uni-kiel.dbp.de (Willi Burmeister) says:
>
>Just a simple (??) question: Why does this small program not work?
>
>------ cut here ------ cut here ------ cut here ------ cut here ------
>#!/bin/sh
>
>cat << EOF > hugo
>one
>two
>three
>four
>EOF
>
>while read num
>do
>  echo "do something with <$num>"
>  last=$num
>done < hugo
>
>echo "last num = <$last>"
>------ cut here ------ cut here ------ cut here ------ cut here ------
>
>the output will always be:
>
>do something with <one>
>do something with <two>
>do something with <three>
>do something with <four>
>last num = <>
>
>
>What I want is:
>
>do something with <one>
>do something with <two>
>do something with <three>
>do something with <four>
>last num = <four>
>            ^^^^

You are using the Bourne shell.  This shell implements the redirection
of the while-loop with a subshell.  And as you probably already
know: you cannot get the variable from the subshell to the parent shell.
(Read also the FAQ about this problem.)
I have been told the Korn shell does this right...

One way round this, using an ugly temporary file:

    trap "rm -f /tmp/sh$$; exit" 0 1 2 3 15
    while read num
    do
        echo "Do something with $num"
        echo $num > /tmp/sh$$
    done << EOF
    one
    two
    three
    EOF
    read last < /tmp/sh$$
    echo last is $last

A better way is to do some manipulation with the filedescriptors.
We can avoid the redirection of the loop like this:

    cat > hugo  << EOF
    one
    two
    three
    EOF

    exec 3<&0 0<hugo   # duplicate the standard input filedescriptor
                       # and redirect it then to read from the file

    while read num     # standard input now reads from file "hugo"
    do
        echo "Doing $num"
        last=$num
    done

    exec 0<&3-         # restore standard input from 3, and close fd 3

    echo last is $last

et voila, it works.  (At least, it works with me.)
--
Polleke   (Paul Bijnens)
Linguistics dept., K. University Leuven, Belgium
FFAAC09 at cc1.kuleuven.ac.be



More information about the Comp.unix.shell mailing list