[comp.unix.shell] SUMMARY Re: sh loop variable and "double indirection"

afc@shibaya.lonestar.org (Augustine Cano) (02/05/91)

I didn't anticipate the great response I got to my questions.  This
newsgroup is an important resource.  Many thanks to the following people,
whose summary of responses follow:

ifas730@ccwf.cc.utexas.edu
Neil Rickert <rickert@cs.niu.edu>
bria!mike@uunet.UU.NET (Michael Stefanik)
qpliu@lyman.pppl.gov (Peter Liu)
raymond@math.berkeley.edu (Raymond Chen)
Roger Cornelius <sherpa!rac@uunet.UU.NET>
mcgrew@ichthous.Eng.Sun.COM (Darin McGrew)
...!uunet!amc.com!stuart (Stuart Poulin)
kinnersley@kuhub.cc.ukans.edu (Bill Kinnersley):



In article <1991Jan27.044258.18779@shibaya.lonestar.org> I wrote:
>I am trying to specify (at run time) an upper limit for a loop in a shell
>script.  In pseudo-code the ideal would be something like this:
>
>read i
>for 0 to i
>do
>...
>done

Just about everybody suggested a while loop with 'expr' to increment
the loop variable.  A typical response was:

echo "enter upper limit"
read limit
i=0
while test $i -lt $limit
do
   # some processing that involves $i here
   i=`expr 1 + $i`
done

The second part of my question was the "double indirection",

>var0=REAL_VALUE0
>var1=REAL_VALUE1
>var2=REAL_VALUE2
>var3=REAL_VALUE3
>var4=REAL_VALUE4
>
>I want to manipulate variable names inside the above loop such that
>I could display the "REAL VALUEx" based on the current value of $i.

Here the solution was also unanimous: the eval command.

One solution was:

read limit
i=0
while [ $i -lt $limit ]
do
    eval echo '$'var$i
    i=`expr $i + 1`
done

"Here's an alternate way to use eval, and maybe a bit clearer."

    eval var='$'var$i
    echo $var

But there's more!  In addition to answering my specific questions,
Roger Cornelius <sherpa!rac@uunet.UU.NET> also supplied the following, which
allowed me to solve another problem I had but had not formulated in my
original posting.

"You need to add braces around a parameter when it's followed by a
letter, digit, or underscore (see Parameter Substitution in your sh
manual page).  You might want to read about eval in the sh man
page also.

x=2 y=5

while test ${x}${y} -gt 0
do
	y=`expr $y - 1`
	echo ${x}${y}
	test $y -eq 0 && x=`expr $x - 1` y=9
done

Also, ...!uunet!amc.com!stuart (Stuart Poulin) added a default value:

#Loop a default of Ulimit times.  I never start at zero as a count.

Ulimit=10
echo enter upper limit
read Ans 

i=1
while [ $i -le ${Ans:-$Ulimit} ]
do
	echo Loop Interation $i
	eval echo \$Var$i
	i=`expr $i + 1`
done
	
Again, many thanks to everyone.

-- 
Augustine Cano		INTERNET: afc@shibaya.lonestar.org
			UUCP:     ...!{ernest,egsner}!shibaya!afc

steve@acorn.co.uk (Steve "daffy" Hunt) (02/12/91)

In article <1991Feb5.003613.21081@shibaya.lonestar.org> afc@shibaya.lonestar.org (Augustine Cano) writes:
>
>
>I didn't anticipate the great response I got to my questions.  This
>newsgroup is an important resource.  Many thanks to the following people,
>whose summary of responses follow:

... more deleted...

I only just subscribed to this newsgroup, so this is rather late, but
my favourite solution to the loop index problem is the following shell
function (just inline it if your shell does not support functions).

# usage: range start end [step]

range () {
	echo "[li p ${3-1} + d si $2!<a] sa ${1}silax" | dc
}

I don't guarantee that your version of dc will be happy with that, but
it works for me!  Making it count backwards, etc, is left as an exercise.

							Steve

-- 
			Steve Hunt	steve@acorn.co.uk

ccsdhd@gdt.bath.ac.uk (Dennis Davis) (02/13/91)

In article <5081@acorn.co.uk> steve@acorn.co.uk (Steve "daffy" Hunt) writes:
>In article <1991Feb5.003613.21081@shibaya.lonestar.org> afc@shibaya.lonestar.org (Augustine Cano) writes:
>>
>>
>>I didn't anticipate the great response I got to my questions.  This
>>newsgroup is an important resource.  Many thanks to the following people,
>>whose summary of responses follow:
>
>... more deleted...
>
>I only just subscribed to this newsgroup, so this is rather late, but
>my favourite solution to the loop index problem is the following shell
>function (just inline it if your shell does not support functions).
>
># usage: range start end [step]
>
>range () {
>	echo "[li p ${3-1} + d si $2!<a] sa ${1}silax" | dc
>}
>
>I don't guarantee that your version of dc will be happy with that, but
>it works for me!  Making it count backwards, etc, is left as an exercise.
>
>							Steve
>
>-- 
>			Steve Hunt	steve@acorn.co.uk

I've always found that languages such as 'dc' are very much
write-only languages.  This is probably a reflection on me rather
than on the language itself.  I'd prefer to write the above more
verbosely using 'bc', as something like:

range ()
{ set `echo $@ | tr '-' '_'`
  echo "if (${3-1} < 0)
        { for (i=$1; i>=$2; i=i+${3-1}) i }
        if (${3-1} > 0)
        { for (i=$1; i<=$2; i=i+${3-1}) i }" | bc
}

The 'set' command is there as a sop to syntactic sugar.  'dc' and
'bc' require that negative numbers are preceeded by a underline
instead of a minus sign.  The 'set' command enables you to write
them more naturally using a minus sign, eg 'range -5 -10 -1'.

The above has (for me) the overwhelming advantages that I can
understand it both now *and* in the future.

... all this is purely academic of course.  No doubt there are far
more elegant solutions using awk, perl etc etc ...
-- 
Dennis Davis            JANET: D.H.Davis@UK.AC.BATH
University of Bath       UUCP: ...!mcsun!ukc!gdr!D.H.Davis
Bath, BA2 7AY     EARN/BITNET: D.H.Davis%uk.ac.bath@UKACRL
England              INTERNET: D.H.Davis%bath.ac.uk@nsfnet-relay.ac.uk