kevin@msa3b.UUCP (Kevin P. Kleinfelter) (08/01/89)
Would anyone who knows, please explain the following behavior? (Post or e-mail, as you deem appropriate.) I enter the following: x=x for i in abc do x=$i done echo $x The output is, as expected, "abc". Then I enter the following: y=y for i in abc do y=$i done < /dev/null echo $y The output is "y", which is exactly what I want to know! ("why"). ***************************************** What I really want to do is to redirect input to "read", but read is non-redirectable (according to my doc, and experience on my system). I was going to attemtpt this as follows for i in 1 do read a b c done < /tmp/foo If I "echo a, b, c" inside the loop, I get the expected values from the file. If I "echo a, b, c" after the loop, I see that they have reverted to their values prior to the loop. Korn Shell has a nice way to resolve this, via an option to "read" to read from a specific file handle. Bourne Shell doesn't. I'm stuck with a system that does not have Korn Shell. :-( -- Kevin Kleinfelter @ Management Science America, Inc (404) 239-2347 gatech!nanovx!msa3b!kevin
bob@wyse.wyse.com (Bob McGowen Wyse Technology Training) (08/04/89)
In article <689@msa3b.UUCP> kevin@msa3b.UUCP (Kevin P. Kleinfelter) writes: >Would anyone who knows, please explain the following behavior? >(Post or e-mail, as you deem appropriate.) ---example code deleted--- > >***************************************** >What I really want to do is to redirect input to "read", but read is >non-redirectable (according to my doc, and experience on my system). ---deleted--- A little know fact about re-directing input to/from an sh loop is that the shell automatically forks another sh to run the loop. Thus, variables changed in the loop do NOT affect variables of the same name in the parent shell. May I suggest the following code to perform your desired redirction to the read command (btw, some newer versions of sh appear to support redirection to the read built-in --- several XENIX scripts I have looked at use this feature): while read line do ... done < file read returns failure on EOF and the loop then exits. Just remember that what you do in the loop may not be available to your script outside of the loop. One way around this would be to save items in a tmp file and either read the tmp file as needed or perhaps use the dot command on it: . tmp Hope this is helpful. Bob McGowan (standard disclaimer, these are my own ...) Customer Education, Wyse Technology, San Jose, CA ..!uunet!wyse!bob bob@wyse.com
maart@cs.vu.nl (Maarten Litmaath) (08/04/89)
kevin@msa3b.UUCP (Kevin P. Kleinfelter) writes:
\...
\ for i in 1
\ do
\ read a b c
\ done < /tmp/foo
\
\If I "echo a, b, c" inside the loop, I get the expected values from the file.
\If I "echo a, b, c" after the loop, I see that they have reverted to their
\values prior to the loop.
Due to the IO redirection the `for' command is executed in a subshell... :-(
\Korn Shell has a nice way to resolve this, via an option to "read" to read
\from a specific file handle. Bourne Shell doesn't. I'm stuck with a system
\that does not have Korn Shell. :-(
Here's an example how to do it:
# save old stdin and IFS
exec 3<&0
OIFS="$IFS"
entry='login passwd uid gid gecos home shell'
IFS=:
exec 0< /etc/passwd
eval read $entry
# restore IFS and stdin
IFS="$OIFS"
exec 0<&3
read a b c
for i in $entry a b c
do
eval echo $i=\$$i
done
In modern Bourne shells you simply use:
read foo < bar
--
"Mom! Eric Newton broke the day! In 24 |Maarten Litmaath @ VU Amsterdam:
parts!" (Mike Schmitt in misc.misc) |maart@cs.vu.nl, mcvax!botter!maart
jdpeek@RODAN.ACS.SYR.EDU (Jerry Peek) (08/13/89)
In article <2346@wyse.wyse.com> bob@wyse.UUCP (Bob McGowen Wyse Technology Training) writes: > ... what you do in the loop may not be available to your script > outside of the loop. One way around this would be to save items > in a tmp file and either read the tmp file as needed or perhaps > use the dot command on it: > > . tmp I think this is a good technique to know, so I decided to post an example of the fix I use. Inside the loop, I use "echo" commands to spit out variable-definition commands. I hook the output of 'echo' onto a less-used file descriptor like 4 -- and catch fd4 into a file at the end of the loop. This code fragment reads in /etc/passwd. After the loop, you can get the first username from $user1, the first uid in $uid1, 20th username from $user20, and so on... This particular example is a quick-and-dirty way to get Bourne Shell "arrays", but it works just as well for plain ol' single-value shell variables: defs=/tmp/defs$$ IFS=":$IFS" # TO PARSE :-SEPARATED FIELDS line=0 # READ /etc/passwd A LINE AT A TIME; STORE GOOD STUFF IN # VARIABLES IN $defs FILE BECAUSE LOOP IS RUN IN A SUB-SHELL: while read user passwd uid junk do line=`expr $line + 1` echo "user${line}='$user' uid${line}='$uid'" 1>&4 done </etc/passwd 4>$defs . $defs # READ VARIABLE DEFINITIONS INTO THIS SHELL The $defs file gets lines like this: user23='freddie' uid23='1032' user24='alice' uid24='1048' then, after the ". $defs" command, you can access $user23, $uid23, etc. BTW, it's more efficient to use "echo 1>&4" and "done 4>$defs", because the $defs file is only opened once while the loop runs. On the other hand, if you simply put "echo >>$defs" into the loop, the shell has to open and close the $defs file for each pass of the loop. --Jerry Peek; Syracuse University Academic Computing Services; Syracuse, NY jdpeek@rodan.acs.syr.edu///JDPEEK@SUVM.BITNET///GEnie: J.PEEK1 +1 315 443-3995
andre@targon.UUCP (andre) (08/14/89)
In article <689@msa3b.UUCP> kevin@msa3b.UUCP (Kevin P. Kleinfelter) writes: >When I enter the following: > y=y > for i in abc > do > y=$i > done < /dev/null > echo $y >The output is "y", which is exactly what I want to know! ("why"). As long as a loop in the shell uses the stdin stdout and stderr of that shell, the loop is executed by that shell, your loop however redirects its stdin. The shell solves this by spawning a subshell that has its stdin redirected. Your second loop is thus executed by a subshell and the value of y stays "y". If you echo the value of y inside the loop you see the right value, but that value cannot be transferred back to the parent shell. Maybe you can try something like, y=y y=`( for i in abc do y=$i done echo $y ) < /dev/null ` I let the </dev/null be there to show where you must put the redirection now. -- \---| AAA DDDD It's not the kill, but the thrill of the chase. \ | AA AAvv vvDD DD Ketchup is a vegetable. /\ \ | AAAAAAAvv vvDD DD {nixbur|nixtor}!adalen.via _/__\__\| AAA AAAvvvDDDDDD Andre van Dalen, uunet!hp4nl!targon!andre
maart@cs.vu.nl (Maarten Litmaath) (08/14/89)
jdpeek@RODAN.ACS.SYR.EDU (Jerry Peek) writes:
\... while read user passwd uid junk
\ do
\ line=`expr $line + 1`
\ echo "user${line}='$user' uid${line}='$uid'" 1>&4
\ done </etc/passwd 4>$defs
Why use fd 4, Jerry? Stdout will do.
--
"Mom! Eric Newton broke the day! In 24 |Maarten Litmaath @ VU Amsterdam:
parts!" (Mike Schmitt in misc.misc) |maart@cs.vu.nl, mcvax!botter!maart
jim@hp-ptp.HP.COM (James_Rogers) (08/17/89)
/ hp-ptp:comp.unix.questions / kevin@msa3b.UUCP (Kevin P. Kleinfelter) / 6:16 am Aug 1, 1989 / >What I really want to do is to redirect input to "read", but read is >non-redirectable (according to my doc, and experience on my system). >I was going to attemtpt this as follows > > for i in 1 > do > read a b c > done < /tmp/foo > >If I "echo a, b, c" inside the loop, I get the expected values from the file. >If I "echo a, b, c" after the loop, I see that they have reverted to their >values prior to the loop. You could try the following form of redirection: for nextfile in a b c do cat $nextfile | { while [ -r $nextfile ] do read aline if [ $? -ne 0 ] then break fi echo $aline done } done I know that this is not pretty, but it does allow you to read through files a, b, and c from the Bourne shell. Jim Rogers at Hewlett Packard Industrial Applications Center Sunnyvale, California
jdpeek@RODAN.ACS.SYR.EDU (Jerry Peek) (08/21/89)
In article <2999@solo1.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes: < jdpeek@RODAN.ACS.SYR.EDU (Jerry Peek) writes: < \... while read user passwd uid junk < \ do < \ line=`expr $line + 1` < \ echo "user${line}='$user' uid${line}='$uid'" 1>&4 < \ done </etc/passwd 4>$defs < < Why use fd 4, Jerry? Stdout will do. Oops. To keep from wasting net bandwidth, I left out things like the error checking (with output to stderr, fd2): echo "`basename $0`: warning: bad line $line" 1>&2 Also, the stdout of the loop (fd1) went to a pipe: done </etc/passwd 4>$defs | some-other-program-or-loop That's why I used fd4 for the variable definitions. BTW, Chris Torek sent mail and pointed out that using fd4 takes time for the extra dup() calls that the shell has to do. Chris didn't know that I'd left out some of the code, but he still has a good point. --Jerry Peek; Syracuse University Academic Computing Services; Syracuse, NY jdpeek@rodan.acs.syr.edu///JDPEEK@SUVM.BITNET///GEnie: J.PEEK1 +1 315 443-3995