[comp.unix.shell] /bin/sh: How to retain variables set in a while loop?

root@lingua.cltr.uq.OZ.AU (Hulk Hogan) (03/05/91)

Hi. I guess this is probably a FAQ, but here goes anyway...
Platform: Sun4.   OS: SunOS 4.x.
I have written some Bourne shell script which sets some variables within 
the body of a while loop. After the loop finishes, the variables are no
longer set.  How can I retain these values after the while loop?
I've tried an export within the body of the while, but that didn't work.

I remember reading somewhere that the body of a while loop is executed in
sub-shell, and that's why the behavious occurs. I really don't care how
the shell does while loops. I just want my variables!

I can use a combination of head, tail and cut to get the results I
want, but it would be so much easier if I could just use while.

Code fragment to assign field 1 of line number $choice to $minuid and
field 2 of it to $maxuid follows.
| num=0
| while [ $num -le $choice ]
| do
|         read minuid maxuid title
|         echo "DEBUG: $num      $title  $minuid         $maxuid"
|         num=`expr $num + 1`
| done < $UIDRANGES
| 
| echo "After while loop: num=$num  title=$title minuid=$minuid maxuid=$maxuid"

/\ndy
-- 
Andrew M. Jones,  Systems Programmer, 	Internet: andy@lingua.cltr.uq.oz.au
Centre for Lang. Teaching & Research, 	Phone (Australia):  (07) 365 6915
University of Queensland,  St. Lucia, 	Phone (World):    +61  7 365 6915
Brisbane,  Qld. AUSTRALIA  4072 	Fax: 		  +61  7 365 7077

"No matter what hits the fan, it's never distributed evenly....."

mcgrew@ichthous.Eng.Sun.COM (Darin McGrew) (03/07/91)

root@lingua.cltr.uq.OZ.AU (Hulk Hogan) writes:
>Hi. I guess this is probably a FAQ, but here goes anyway...
>Platform: Sun4.   OS: SunOS 4.x.
>I have written some Bourne shell script which sets some variables within 
>the body of a while loop. After the loop finishes, the variables are no
>longer set.  How can I retain these values after the while loop?
>I've tried an export within the body of the while, but that didn't work.
>
>I remember reading somewhere that the body of a while loop is executed in
>sub-shell, and that's why the behavious occurs. I really don't care how
>the shell does while loops. I just want my variables!

If the while loop has its stdio redirected in any way, it is put
in a subshell.  (Likewise with for loops, case statements, etc.)
The subshell has no way to pass variables back to its parent
shell.

>I can use a combination of head, tail and cut to get the results I
>want, but it would be so much easier if I could just use while.

Another approach would be to write the values of the variables
into temporary files, and then read them back, but that isn't
really a great solution either.

I'd try avoiding putting the while loop into a subshell by doing
the io redirection in the parent shell.  Your example becomes--

    exec < $UIDRANGES
    num=0
    while [ $num -le $choice ]
    do
         read minuid maxuid title
         echo "DEBUG: $num      $title  $minuid         $maxuid"
         num=`expr $num + 1`
    done < $UIDRANGES
 
    echo "After while: num=$num title=$title minuid=$minuid maxuid=$maxuid"

If you need your original io at some point after the while loop,
there are games you can play with `exec 3<&0` and `exec 0<&3` to
save stdin as file descriptor 3 (typically unused) beforehand,
and then restore stdin from file descriptor 3 when you're done.

                 Darin McGrew
           mcgrew@Eng.Sun.COM   "Christianity isn't a crutch; it's a stretcher.
       Affiliation stated for    You can't even hobble into heaven."
identification purposes only.

mcgrew@ichthous.Eng.Sun.COM (Darin McGrew) (03/07/91)

In article <9209@exodus.Eng.Sun.COM> I write:
>I'd try avoiding putting the while loop into a subshell by doing
>the io redirection in the parent shell.  Your example becomes--
>
>    exec < $UIDRANGES
>    num=0
>    while [ $num -le $choice ]
>    do
>         read minuid maxuid title
>         echo "DEBUG: $num      $title  $minuid         $maxuid"
>         num=`expr $num + 1`
>    done < $UIDRANGES
> 
>    echo "After while: num=$num title=$title minuid=$minuid maxuid=$maxuid"

This should really be--

    exec < $UIDRANGES
    num=0
    while [ $num -le $choice ]
    do
         read minuid maxuid title
         echo "DEBUG: $num      $title  $minuid         $maxuid"
         num=`expr $num + 1`
    done
 
    echo "After while: num=$num title=$title minuid=$minuid maxuid=$maxuid"

since the point was to eliminate the io redirection of the while
loop.

                 Darin McGrew
           mcgrew@Eng.Sun.COM   "Christianity isn't a crutch; it's a stretcher.
       Affiliation stated for    You can't even hobble into heaven."
identification purposes only.

jik@athena.mit.edu (Jonathan I. Kamens) (03/07/91)

In article <9209@exodus.Eng.Sun.COM>, mcgrew@ichthous.Eng.Sun.COM (Darin McGrew) writes:
|> If the while loop has its stdio redirected in any way, it is put
|> in a subshell.  (Likewise with for loops, case statements, etc.)
|> The subshell has no way to pass variables back to its parent
|> shell.

  I just want to point out that this problem is eliminated in some newer
versions of the bourne shell, and also in some other shells (including, I
believe, bash and ksh) that use the bourne shell's language.

  Of course, the C shell gets around the problem by not allowing redirection
into loops at all :-).

-- 
Jonathan Kamens			              USnail:
MIT Project Athena				11 Ashford Terrace
jik@Athena.MIT.EDU				Allston, MA  02134
Office: 617-253-8085			      Home: 617-782-0710