dennis@rlgvax.UUCP (Dennis Bednar) (02/04/87)
While writing a shell script, I found an unexpected behavior that I thought I would share with the net. In summary, apparently for i do var=xxx done >/tmp/tmpfile causes the shell interpreter to run a sub-shell, and so the value of $var set in the middle of a for loop is lost if $var is referenced after the for loop. IS THIS CONSIDERED TO BE A sh(1) bug? The first shell script below named "t" fails, in that if run as "t -A", it prints AFLAG = 0, not AFLAG = 1, at the end, even though AFLAG is set to 1 in the for loop. However, if, the ">/tmp/t$$" is removed from the file "t", the problem goes away. Since I needed to capture the output into a temp file /tmp/t$$, I fixed it by modifying "t" to save the AFLAG variable in a temp file. The fixed version I came up with is called "t2". Here is the output, when run on our machine (cci632 Sys5 r2): Script started on Tue Feb 3 16:35:35 1987 $ t -A 1: AFLAG = 1 2: AFLAG = 0 $ t2 -A 1: AFLAG = 1 2: AFLAG = 1 $ script done on Tue Feb 3 16:35:47 1987 Below are two very short scripts "t" and "t2". #--------------- CUT HERE --------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # t # t2 # This archive created: Tue Feb 3 16:45:34 EST 1987 # if test -f t then echo shar: will not over-write existing file 't' else echo x - t # ............ F I L E B E G .......... t cat << '\SHAR_EOF' > t AFLAG=0 for i do if [ $i = -A ] then AFLAG=1 echo "1: AFLAG = $AFLAG" 1>&2 # to stderr not to tmp file continue fi done >/tmp/t$$ echo 2: AFLAG = $AFLAG rm -f /tmp/t$$ \SHAR_EOF # ............ F I L E E N D .......... t fi # end of overwriting check if test -f t2 then echo shar: will not over-write existing file 't2' else echo x - t2 # ............ F I L E B E G .......... t2 cat << '\SHAR_EOF' > t2 AFLAG=0 for i do if [ $i = -A ] then AFLAG=1 echo "1: AFLAG = $AFLAG" 1>&2 # to stderr not to tmp file echo $AFLAG >/tmp/T$$ # pass flag via file continue fi done >/tmp/t$$ AFLAG=`cat /tmp/T$$` echo 2: AFLAG = $AFLAG rm -f /tmp/t$$ /tmp/T$$ \SHAR_EOF # ............ F I L E E N D .......... t2 fi # end of overwriting check # end of shell archive exit 0 -- FullName: Dennis Bednar UUCP: {seismo|sundc}!rlgvax!dennis USMail: CCI; 11490 Commerce Park Dr.; Reston VA 22091 Telephone: +1 703 648 3300
dcm@sfsup.UUCP (02/06/87)
In article <354@rlgvax.UUCP> dennis@rlgvax.UUCP writes: >While writing a shell script, I found an unexpected behavior >that I thought I would share with the net. > >In summary, apparently > >for i >do > var=xxx >done >/tmp/tmpfile > >causes the shell interpreter to run a sub-shell, and so the value >of $var set in the middle of a for loop is lost if $var is referenced >after the for loop. IS THIS CONSIDERED TO BE A sh(1) bug? > >-- >FullName: Dennis Bednar >UUCP: {seismo|sundc}!rlgvax!dennis >USMail: CCI; 11490 Commerce Park Dr.; Reston VA 22091 >Telephone: +1 703 648 3300 Yes, this is a know shell bug. It also occurs with a structure like this: while read var do # anything done < /tmp/tmpfile If you happen to have ksh, I'd suggest using that, since this bug has been fixed there. Ksh doesn't spawn a new shell to do the redirection. Anybody have diffs to fix /bin/sh to work this way? Dave -- David C. Miller, consultant Communications Interface Addresses: Paperware: AT&T Information Systems, 190 River Road, Summit, NJ 07901 Liveware: (201) 522-6107 Software: {allegra,burl,cbosgd,clyde,ihnp4,ulysses}!sfsup!dcm ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ On good days life is T.A.N.S.T.A.A.F.L. On days like today: T.A.N.S.T.A.A.L. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dce@mips.UUCP (02/06/87)
No, this is not considered to be a bug. When you do redirection or pipes
of any kind, the shell forks. This is done because getting back to the
original file state would be impossible if you tried to do it locally.
Basically, it would be almost impossible to handle the case in which
you execute
shell_script < foo > bar
if there was some internal redirection inside of the shell script.
The shell couldn't save the file descriptors somewhere else because
it would run out of descriptors (ever hear of the 'fd>file' syntax?).
Thus, the shell has to fork to the the redirection.
Now, if your problem is that you need a way to assign a variable
during a redirection and have that value available afterwards, you have
a couple of possibilities:
1. Place the variable value in a file, and use
VAR="`cat file`"
2. You can get tricky, as in
#!/bin/sh
exec 9>&1 # save stdout in fd 9
exec 1>bar # stdout->file "bar"
for i in 1 2 3 4 5
{
var="$i"
echo "hello" # output goes in file "bar"
}
exec 1>&9 # stdout->saved stdout
echo "$var"
I use file descriptor 9 here to stand out, but I believe that
all file descriptors other than 0, 1, and 2 are closed upon
execution of subprocesses, so you should be able to use anything
from 3 to 9 (2-digit fds are syntax errors). Can Guy or Doug
or someone verify this?
--
David Elliott
UUCP: {decvax,ucbvax,ihnp4}!decwrl!mips!dce, DDD: 408-720-1700
jerryp@tektools.UUCP (02/06/87)
[I've restricted this followup to comp.unix.questions only.] In article <354@rlgvax.UUCP> dennis@rlgvax.UUCP (Dennis Bednar) writes: > In summary, apparently > > for i > do > var=xxx > done >/tmp/tmpfile > > causes the shell interpreter to run a sub-shell, and so the value > of $var set in the middle of a for loop is lost if $var is referenced > after the for loop. IS THIS CONSIDERED TO BE A sh(1) bug? You're right about the loop: it runs in a sub-shell. (This is true with the Berkeley Bourne shell, at least.) The same thing happens with redirected input, as in: someprog | while read line do ...set some shell variables... done shell variables set inside the loop won't be available outside of it. I think it's a well-known bug [anyone vote for calling it a feature? :-)] It's fixed, at least partially, in the Korn Shell. --Jerry Peek, Tektronix, Inc. US Mail: MS 74-900, P.O. Box 500, Beaverton, OR 97077 uucp-style: {allegra,decvax,hplabs,ihnp4,ucbvax}!tektronix!tektools!jerryp Domain-style: jerryp@tektools.TEK.COM Phone: +1 503 627-1603
gwyn@brl-smoke.UUCP (02/08/87)
In article <2171@tektools.TEK.COM> jerryp@tektools.TEK.COM (Jerry Peek) writes: >shell variables set inside the loop won't be available outside of it. The /bin/sh distributed with 4.nBSD (for n <= 4, at least) is a really old, buggy, puny version of the Bourne shell. I was going to supply a modern version for 4.3BSD but Berkeley balked at requiring a UNIX System V source license of their "customers". The current edition of the BRL SVR2 shell can be easily configured to replace a 4BSD /bin/sh. (Info about this was posted not long ago, so I won't repeat it here.)
guy@gorodish.UUCP (02/17/87)
>>shell variables set inside the loop won't be available outside of it. > >The /bin/sh distributed with 4.nBSD (for n <= 4, at least) is a really >old, buggy, puny version of the Bourne shell. Unfortunately, the new, bug-fixed, whizzy version supplied with System V, Releases 2 and 3 does the exact same thing.