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