Thanks, Phil and Jack!  You've explained it.

Adam wrote:
>>> #!/bin/bash
>>> CONTENTS="xyz"
>>> N=1
>>> echo "$CONTENTS" | while read LINE ; do
>>>         N=4
>>>         echo N = $N
>>> done
>>> echo N is now $N
>>>
>>> [EMAIL PROTECTED] ~]$ ./d
>>> N = 4
>>> N is now 

On Fri, Sep 12, 2008 at 9:56 PM, Phil M Perry <[EMAIL PROTECTED]> wrote:
>> What is the echo "$CONTENTS" | while-command supposed to do? I don't
>> think I've seen that idiom before. I suspect that it's creating some sort
>> of
>> local environment within it (piping to a new process?) so that a new "N" is
>> created just for that little bit. Does $LINE exist after the echo/loop?
>>     
Nope, both N and LINE vanish after the loop.  That would also explain 
why it works the way I'd expect if instead of "echo | while" it's just 
plain "while":

while [ $N -lt 5 ] ; do
    let N=N+1
etc.

Jack Chastain wrote:
> Phil is on the right track - you are using a pipeline to create your while
> loop - which is running in a new process.
>
> ksh doesn't do this - but bash and Bourne do.
>   
That would explain it -- it was suggested to me as a way to use 
variables instead of temporary files -- but by someone whose experience 
is with ksh, not bash.  I gather that if I'm going to learn how to write 
scripts for one shell, it ought to be bash, as that's the most ubuquitous.
> An interesting experiment -  truss the entire script when you run it:
>
> truss ./d
>
> You should see the entry - and exit - from the subshell.
>   
Mandriva doesn't seem to have 'truss'.  I tried 'strace' but the 
subshell didn't seem obvious.
> I haven't been able to find a way to transport the variable with this code
> but if it is needed, would suggest something along the lines of:
>
>   for LINE in $CONTENTS; do
>
> This can be an issue if "$CONTENTS" contains spaces or other whitespace.
In the actual script, $CONTENTS will contain several lines and other 
whitespace, something like:

CONTENTS=$(ls -d D*)
echo $CONTENTS | while read LINE ; do
    {process next line of CONTENTS, assign to FOO}
    RESULTS="$RESULTS
    $FOO"
done
echo $RESULTS >> $OUTPUTFILE

Presumably this works under ksh.
> There must be hundreds of other options.
>   
I think I'll use:

CONTENTS=$(ls -d D*)
echo $CONTENTS | while read LINE ; do
    {process next line of CONTENTS, assign to FOO}
    echo $FOO >> $TMP1
done
# only modify OUTPUTFILE if everything has been successful
cat $TMP1 >> $OUTPUTFILE

This does use one temporary file, but that still should be more 
efficient.  I'd been sending the output of 'ls' to a file, and was using 
three temporary files.  I'll pass this info back to the ksh programmer 
too.  Thanks again!

Adam

_______________________________________________
Mid-Hudson Valley Linux Users Group                  http://mhvlug.org          
   
http://mhvlug.org/cgi-bin/mailman/listinfo/mhvlug                           
Upcoming Meetings (6pm - 8pm)                         MHVLS Auditorium          
        
  Sep 3 - Porkchop - The Areas of My Expertise
  Oct 1 - Ubikeys
  Oct 4 - Linux Fest
  Nov 5 - Releasing Open Source Software
  Dec 3 - TBD
  

Reply via email to