Shell Script Question

Brad De Vries devriesbj
Fri Jun 3 09:32:49 PDT 2005


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.



More information about the Linux-users mailing list