gfs@drutx.UUCP (SkinnerGF) (03/01/85)
.......... Here is a very simple program to print out your directories variable=none echo "directories" for filename in `ls` do if test -d $filename then variable=some echo $filename fi done | pr -t4 echo $variable HOWEVER, variable will always be none wheather or not anything was found! further debugging shows that variable = some before exiting the pipe but, variable = none after exiting the pipe. Why does the pipe do this? Thanks in advance ..... gary skinner drutx!gfs
henry@utzoo.UUCP (Henry Spencer) (03/03/85)
The pipe is causing the main shell to spin off a child shell to run the innards of the for-loop. The result is that the variable is local to the child, and naturally doesn't propagate back into the parent since there is no path by which it might do so. You have just encountered Excedrin Headache number 3.14159 for shell programmers. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (03/03/85)
> for ... > do > variable=some > done | ... > echo $variable The problem is that `variable' is being set in a forked subshell. I don't know of any simple way around this.
johnl@ima.UUCP (03/04/85)
Congratulations! You have tripped over one of the most peculiar parts of the Bourne shell. The problem is this: the shell only knows how to do I/O redirection for processes, not for builtin commands. This means that if you redirect I/O for a command, it gets forked into a subprocess silently and confusingly. For example: a=one for i in two three four do a=$i done > plugh echo $a The result is "one" because the for loop is done in a subprocess, and the modifications to variable a in the subprocess don't affect the top level shell. See Steve Bourne's book "The Unix System" for some extremely gross ways to work around this. (I suppose that since it's his shell, he gets to program it any way he wants, though.) Also, the System V shell is somewhat smarter about I/O redirection, so some things like "read foo <bar" which used not to work now do. John Levine, ima!johnl
terryl@tekcrl.UUCP () (03/04/85)
>variable=none >echo "directories" >for filename >in `ls` >do > if test -d $filename > then variable=some > echo $filename > fi >done | pr -t4 >echo $variable > >HOWEVER, variable will always be none wheather or not anything >was found! further debugging shows that variable = some before >exiting the pipe but, variable = none after exiting the pipe. >Why does the pipe do this? Because of the pipe, the shell has to fork off two processes for both sides of the pipe, i.e. the for loop and the pr command. So, what is in reality happening is that there are three processes running: the original process for the shell script, the first subprocess for the for loop, and the second sub- process for the pr command. Since you are executing the for loop in a sub- process, all variables set inside the for loop only have their true value as long as the for loop is running. If you take out the pipe, then things work as you expected. Terry Laskodi of Tektronix
quenton@ecr.UUCP (Dennis Smith) (03/05/85)
The shell file in question piped a "for" loop into "pr". Inside the "for" loop, a shell variable was set. The question was - why is the variable not set after the "for .. | pr" is over? One must recognize when the shell, in its perverted manner, fires up new processes or forked copies of itself to do things. In this case, the shell has obviously forked a copy of itself to handle the "for", because it is piped. Thus the variable set inside the for was actually set (and lost) in another shell process. It would seem that sh does not really have to do this unless the whole mess was followed by &, but it seems to.
mab@druxp.UUCP (BlandMA) (03/07/85)
Just to confuse matters a little more, ksh (the Korn shell) handles this situation better than the Bourne shell, but still isn't perfect. ima!johnl gave the following example: a=one for i in two three four do a=$i done >plugh echo $a Using sh, the result is a=one. But ksh gives the desired result of a=four. In the interest of efficiency, ksh tries not to fork extra shells when possible, and this is apparently one of those situations. Unfortunately, the following slightly modified version of the example, using a pipe instead of a file for output, results in a=one with both sh and ksh. Sigh. a=one for i in two three four do a=$i done | cat echo $a Hey! Maybe we can add an option to "cat" to make this work! :-) -- Alan Bland {ihnp4, allegra}!druxp!mab AT&T Information Systems Labs, Denver