mellman@ttrdd.UUCP (09/24/87)
When I set a variable in a while loop in a sh script, in some scripts it doesn't seem to get set. For example, a common thing is to do a pipeline | while read proc do and then to test for some condition in a case statement. Twice now, I have written scripts where a variable set in the case loop (or anywhere in the while loop, for that matter) won't have been changed from its initial value after the while loop terminates. Can anyone explain to me why this is so. For example, I have a little script that will log me off of my 630 terminal by nohup-ing the login process - as long as only insignificant processes are still running: # # This script will shutdown my account # PATH=$HOME/bin:/bin:/usr/bin:/usr/lbin options="xd" arglist="" optlist="" set -- `getopt $options $*` if [ $? != 0 ]; then echo "Usage: $0 [$options]" exit -1 fi for arg in $*; do case $arg in --) shift break ;; -d) execute=2 export execute shift ;; -x) execute=1 export execute shift ;; esac done ps -u$LOGNAME | awk '{print $4}' | while read proc do execute=3 case $proc in sysmon | awk | ksh | ps | layers | COMMAND) ;; "") echo '\007\007' defunct process? execute=0 export execute ;; *) echo '\007\007' $proc still running execute=0 export execute ;; esac done echo execute is $execute if [ $? -eq 0 ]; then if [ ${execute:-0} -eq 1 ]; then kill -1 ${fatherpid:-"fatherpid not set"} else echo ${fatherpid:-"fatherpid not set"} fi fi But, at the echo, it can be seen that execute never got set during the while loop. It's driving me crazy. Any help would be appreciated.
scl@virginia.acc.virginia.edu (Steve Losen) (09/28/87)
In article <212@ttrdd.UUCP> mellman@ttrdd.UUCP (Thomas Mellman) writes: >When I set a variable in a while loop in a sh script, in some scripts >it doesn't seem to get set. For example, a common thing is to do a > > pipeline | while read proc > do done # assumed What is happening is that the while loop is being run as a separate process. The shell is very fond of doing this sort of thing, especially in pipelines. At the "done" the "while loop process" exits, giving control back to the parent shell, whose variables haven't changed. I suggest that you do this: pipeline | ( while read proc do # set some variables done # now use the variables set in while loop ) This forces everything between the parentheses to happen in the child process, so you can get some use out of those variables. -- Steve Losen University of Virginia Academic Computing Center
wietse@eurifb.UUCP (Wietse Venema) (09/29/87)
In the Bourne shell for/case/while/if-else-fi constructs are executed by a child process when the output or input of such a construct is redirected, e.g. when it is part of a pipe. Wietse Venema (uucp: mcvax!eutwc1!wietse) (bitnet: wswietse@heithe5)
crc@abvax.icd.ab.com (Clive R. Charlwood) (09/29/87)
in article <212@ttrdd.UUCP>, mellman@ttrdd.UUCP (Thomas Mellman) says: > > When I set a variable in a while loop in a sh script, in some scripts > it doesn't seem to get set. For example, a common thing is to do a > > pipeline | while read proc > do > > and then to test for some condition in a case statement. Twice now, I > have written scripts where a variable set in the case loop (or anywhere > in the while loop, for that matter) won't have been changed from its > initial value after the while loop terminates. Can anyone explain to me > why this is so. In the bourne shell while/for loops that have stdin redirected are implemented as sub shells. Thus any changes to variables 'disapear' when the shell exits. Clive Clive R. Charlwood @ Allen-Bradley Company Industrial Computer Division 747 Alpha Drive, Highland Heights, OH 44143 ...!{decvax,masscomp,pyramid,cwruecmp}!abic!crc -- Clive R. Charlwood @ Allen-Bradley Company Industrial Computer Division 747 Alpha Drive, Highland Heights, OH 44143 ...!{decvax,masscomp,pyramid,cwruecmp}!abic!crc
jws@hpcllf.HP.COM (John Stafford x75743) (09/29/87)
Shell script loops with any I/O of the loop as a whole redirected (i.e. stdin in your case) are run in a separate (sub-)shell process and so changes in variables in such loops obviously are not reflected in the parent. Loops without redirected I/O are run in the current shell and so changes in variables work. This is either not documented or obscurely documented. I have "gotten around" this feature by writing things into temporary files and having the parent get them from there: # Replace VARIABLE="" with temp=/tmp/x$$ trap "rm -f $temp" 0 1 2 3 15 # Don't leave a mess cp /dev/null $temp # >$temp would work also process | while read something do # Replace VARIABLE="$VARIABLE $something" with echo " $something" >>$temp done VARIABLE="`cat temp`" It isn't perhaps the cleanest, but it works. John Stafford -- Hewlett Packard Computer Language Lab {allegra,decvax,ihnp4,ucbvax}!hplabs!hpclla!jws {fortune,sun,thirdi,ucbvax} !hpda !hpclla!jws