Shell Script Question

Mike Reinehr cmr
Fri Jun 3 10:53:21 PDT 2005


On Friday 03 June 2005 09:42 am, Brad De Vries wrote:
> On 6/2/05, Mike Reinehr <cmr at amsent.com> wrote:
> > On Thursday 02 June 2005 08:12 am, Brad De Vries wrote:
> > > On 6/1/05, David Bandel <david.bandel at gmail.com> wrote:
> > > > Wonder why this reply didn't go to the list?
> > > >
> > > > On 6/1/05, Alma J Wetzker <almaw at ieee.org> wrote:
> > > > > I don't do much scripting beyond expect, can you have more than one
> > > > > return value to a script?  I counted three desired variables.  Is
> > > > > there a way to get all three out without going to global?
> > > > >
> > > > > In C, I would pass two by reference and return the third.  Can you
> > > > > do weird stuff like that in a script?
> > > >
> > > > Good question.  And the answer is:  I don't have a clue.  And it
> > > > could be different between ksh, bash, bash2, and bash3.  As soon as
> > > > something really needs more than very simple scripting, I drop into
> > > > Perl mode.  In Perl I can pass several variables to a subroutine, no
> > > > reference needed (although Perl can do all those memory tricks of
> > > > passing a memory address of a variable).  And there are ways to get
> > > > them back out, too.
> > > >
> > > > Brad, what shell are you calling and have you tried calling a
> > > > different one?  Last time I worked on AIX and HP-UX, they didn't have
> > > > bash.  They had borne and korn shells and that was about it (unless
> > > > you liked to abuse yourself with a C-shell -- which should only be
> > > > sold down by the sea shore).
> > > >
> > > > Ciao,
> > > >
> > > > David A. Bandel
> > >
> > > I use the bourne shell (#!/bin/sh) for virtually all my scripts
> > > because I deal with several UNIX variants (including cygwin and MKS
> > > Toolkit, UNIX environments on Windows.)  I would love to use perl for
> > > many of my projects but I can't always guarantee that it will be
> > > installed and trying to get a sys-admin to install perl when they've
> > > gone without it for 10+ years is a little like trying to push a rope.
> > > Sadly I don't push too hard because I know shell scripting but my perl
> > > skills are pretty weak.
> > >
> > > I would guess that 90-95% of all my scripts work perfectly everywhere
> > > I go with the one big exception of this looping issue.  Stuff I wrote
> > > in the late 80's worked this way and when I started working with Linux
> > > and bash I found it worked differently.  Now I know why.
> > >
> > > To answer Alma's question about passing variables by reference, I'd
> > > have to say that the shell does not have that ability.  Actually,
> > > until I started working with AIX and ksh, I'd never even heard of that
> > > concept of local variables in shell scripts.  Ksh and bash, there may
> > > be others, allow the you to define local variables but in sh and csh
> > > every variable that you create is global.
> > >
> > > Brad.
> >
> > Brad,
> >
> > Your scripting skills appear to be far past mine, but my experience with
> > sh has been that all variables are global. I just ran a quick test of a
> > script similar to yours and, in fact, they were. A couple of differences
> > that might be significant:
> >
> > I initialized my variables the old fashioned way:
> >
> > export TEMP=0 TEMP1=1 TEMP2=2
> >
> > and used the expr command to do the calculations:
> >
> > TEMP=`expr $TEMP + 1`
> >
> > etc, ...
> >
> > When I broke from the for/do loop all values were retained as expected.
> >
> > HTH's!
> >
> > cmr
>
> Mike, you are 100% correct that the values will be retained after
> leaving a for/do loop.  The reason, however, is not because of the
> "export" but because the for/do loop does not spawn a sub-shell for
> the execution.  In my example code and my comments, I referred to the
> while-loop but I think I was misleading.  The real problem in my
> script was the pipe command "ls | while read file; do".  The pipe
> caused the entire loop to run in a sub-shell which cannot pass values
> back up to the parent's environment variables.  Try this little
> example to see it in action:
>
> ----
> TOTAL=0
> LIST="1 2 3 4 5 6 7 8 9 10"
> for item in ${LIST}; do
>   echo "  Counting ${item}"
>   TOTAL=`expr ${TOTAL} + 1`
> done
> echo "for/do loop TOTAL=${TOTAL}"
> echo
>
> TOTAL=0
> ls | while read item; do
>   echo "  Counting ${item}"
>   TOTAL=`expr ${TOTAL} + 1`
> done
> echo "ls | while/do loop TOTAL=${TOTAL}"
> ----
>
> The first loop will show you the total equals 10, which is correct.
> The second execution, which counts the number of files in the current
> directory, returns a total of zero, which is incorrect (assuming
> you've got at least one file in the current directory.)
>
> I was using the "ls | while ..." structure but since bash works
> differently than ksh and sh, I had to change to:
> ls > /tmp/list
> while read item; do
>  ...
> done < /tmp/list
>
> This will not execute in a sub-shell, because there's no pipe, so it
> works as I expected.  It's not as clean as the old way but it works in
> bash, ksh and sh so I'll have to live with it.
>
> I hope that makes it a bit clearer.
>
> Brad.

Brad,

Ahaaa! Thanks for clearing that up. It never occurred to me that the pipe 
would spawn a subshell.

Here's another way that seems to work without the pipe, or a temp file:

for i in `ls`
do
...

Ok, I can go home now. I've learned my one new thing for the day. ;-)

cmr

-- 
Debian 'Sarge': Registered Linux User #241964

"More laws, less justice." -- Marcus Tullius Ciceroca, 42 BC


More information about the Linux-users mailing list