Subject: Re: Variables in Loops in Scripts
To: C Kane <ckane@best.com>
From: Roger Brooks <R.S.Brooks@liverpool.ac.uk>
List: netbsd-help
Date: 01/20/1999 11:23:00
On Tue, 19 Jan 1999, C Kane wrote:
>I have a simple sh/ksh script which works okay under
>Solaris and HP-UX, but fails in the same way under
>NetBSD and Linux. After the "do" loop is over, the
>variables that are set inside the loop revert to their
>previous before-the-loop values. What am I doing wrong
>in the following script?
>
>#!/bin/ksh
>
>ps -ax | while read PID TT STAT TIME COMMAND ARGS
>do
> case $COMMAND in
> syslogd ) SYSLOGD=$PID ;;
> portmap ) PORTMAP=$PID ;;
> update ) UPDATE=$PID ;;
> esac
> echo syslogd=$SYSLOGD portmap=$PORTMAP update=$UPDATE
>done
>
>echo FINAL syslogd=$SYSLOGD portmap=$PORTMAP update=$UPDATE
It's due to subtle (but crucial) differences between the NetBSD ksh and
the "official" USL version when the last component in a pipeline is a
shell builtin. USL ksh runs the builtin in the parent process, whereas
NetBSD ksh runs it in a child. I hit a similar problem a few months ago
with something like:
print $foo | IFS=: read a b c
print $a $b $c
The read runs in a child, so the second print doesn't output anything.
I produced a fix which cured this problem, and in poring over the
code I realised there was a similar problem if the last component in
a pipeline was a loop. I *think* I fixed that as well, but wasn't sure
I'd done enough testing to submit the patch. There's also the question
of constructs like:
somecommand | if ... fi
and
somecommand | case ... esac
where shell builtins within the if ... fi (or case ... esac) ought to run
in the parent shell. Furthermore, I didn't test the behaviour of all the
other shell builtins which should always be run in the parent shell (and
which could feasibly appear in a compound command at the end of a pipeline).
I'll try your example on my patched ksh and see if it works, although I
doubt I'll have time to do it until the weekend. Meanwhile, a quick fix
is to put the output from ps into a temporary file and redirect the input
of the do loop from this (yuk!).
AFAIK, always running the last component of a pipeline in a child is
correct behaviour for the Bourne shell. It's one of the differences
between sh and ksh.
Roger
------------------------------------------------------------------------------
Roger Brooks (Systems Programmer), | Email: R.S.Brooks@liv.ac.uk
Computing Services Dept, | Tel: +44 151 794 4441
The University of Liverpool, | Fax: +44 151 794 4442
PO Box 147, Liverpool L69 3BX, UK |
------------------------------------------------------------------------------