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

afc@shibaya.lonestar.org (Augustine Cano) (01/27/91)

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

The closest I've come to this is what follows:

echo "enter upper limit"
read limit
for i in 0 1 2 3 4 5 6 7 8 9
do
# some processing that involves $i goes here
if test $i -ge $limit-1 ; then	# NOTE: for i=3, I want iterations 0,1,2
  break
fi
done

Not very elegant since a limit of 10 iterations is hard-wired.  Can anybody
think of a more concise way to do this?  Using PERL is not an option, this
must be portable sh code.

The next problem is the thorny one.  Some shell variables having been
previously set up, say:

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.

At the prompt, with the above variables initialized, echo $var0,
echo $var1, etc... yield the expected results.  When I put
echo $var$i in the loop, it doesn't work.  Other variations, such as
echo $"$var$i", etc... don't work either.  How can this be done?

How is it possible to make sh group $var and $i first and then get the
real value of the variable that results from combining the 2 strings?

Any help will be greatly appreciated!!!  I'll summarize e-mail responses.

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

]) (01/28/91)

In article <1991Jan27.044258.18779@shibaya.lonestar.org> afc@shibaya.lonestar.org (Augustine Cano) writes:
>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

Let me give you the ksh version first, then the (slower) sh mods -- it's
slower because each iteration requires a fork/exec not required in ksh.

:
# ksh version
# (note -- in commentary, Augustine requests that we stop at i-1)
typeset -i i j	# make things run faster by naming these as ints
j=0		# could be done on the typeset, but needed for the sh version

echo "enter limit: \c"
read i dummy	# in case we get two words; also, you should test for a bad $i
while [ $j -lt $i ]
do
	eval 'var'$j'="$REAL_VALUE'$j'"'
	eval 'echo "var$j is $var'$j'"'
	((j = $j + 1))
done
exit

The sh version is the same except for two parts:  delete the typeset,
because it's not in sh, and replace   ((j = $j + 1))  with a call
j=`expr $j + 1`  (which is the extra fork/exec).

>Not very elegant since a limit of 10 iterations is hard-wired.  Can anybody
>think of a more concise way to do this?  Using PERL is not an option, this
>must be portable sh code.
>
>The next problem is the thorny one.  Some shell variables having been
>previously set up, say:
>
>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.

Assuming that all possible REAL_VALUE* variables were defined somehow,
the two eval instructions inthe sample loop will store their contents
in the variables  var0 through var${i-1} and print them out.  If you're
a Rexx programmer, eval in the shell is like Rexx's interpret.  The args
to eval are evaluated once (losing one level of quotation), the 'eval '
is stripped, and the resulting string is evaluated and executed.

...Kris
-- 
Kristopher Stephens, | (408-746-6047) | krs@uts.amdahl.com | KC6DFS
Amdahl Corporation   |                |                    |
     [The opinions expressed above are mine, solely, and do not    ]
     [necessarily reflect the opinions or policies of Amdahl Corp. ]

mcgrew@ichthous.Eng.Sun.COM (Darin McGrew) (01/29/91)

afc@shibaya.lonestar.org (Augustine Cano) writes:
>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

I'd use a while loop, as such:

	read max	# Note: there is no sanity check of $max
	counter=0
	while [ $counter -le $max ]
	do
		...
		counter=`expr $counter + 1`
	done

>The next problem is the thorny one.  Some shell variables having been
>previously set up, say:
>
>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.

You need to use the eval operator.  The first evaluation will get
the value of $i, and the second one (ie, the one caused by the
eval operator) will use that value as part of the for loop:

	eval echo \$var$i

                 Darin McGrew     "The Beginning will make all things new,
           mcgrew@Eng.Sun.COM      New life belongs to Him.
       Affiliation stated for      He hands us each new moment saying,
identification purposes only.      'My child, begin again....
				    You're free to start again.'"

maart@cs.vu.nl (Maarten Litmaath) (01/29/91)

In article <a21801wv11X.00@amdahl.uts.amdahl.com>,
	krs@uts.amdahl.com (Kris Stephens [Hail Eris!]) writes:
)In article <1991Jan27.044258.18779@shibaya.lonestar.org>
)	afc@shibaya.lonestar.org (Augustine Cano) writes:
)>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
)
)Let me give you the ksh version first, then the (slower) sh mods -- it's
)slower because each iteration requires a fork/exec not required in ksh.

Not necessarily.

	read i

	t0= rest='1 2 3 4 5 6 7 8 9'

	for h in '' $rest
	do
		for t in "$t0" $rest
		do
			for u in 0 $rest
			do
				case $h$t$u in
				999)
					echo overflow >&2
					exit 1
					;;
				$i)
					break 3
				esac
				do_something
			done
		done
		t0=0
	done

This example works for 999 iterations.  Enough?
--
kinnersley@kuhub.cc.ukans.edu (Bill Kinnersley):
	"Do phonograph turntables turn the other way in Australia?"
gjh@krebs.acc.Virginia.EDU (Galen J. Hekhuis):
	"How do you think satanic messages were discovered on records?"

bob@wyse.wyse.com (Bob McGowen x4312 dept208) (02/02/91)

In article <a21801wv11X.00@amdahl.uts.amdahl.com> krs@amdahl.uts.amdahl.com (Kris Stephens [Hail Eris!]) writes:
>In article <1991Jan27.044258.18779@shibaya.lonestar.org> afc@shibaya.lonestar.org (Augustine Cano) writes:
>>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

deleted ksh stuff

>The sh version is the same except for two parts:  delete the typeset,
>because it's not in sh, and replace   ((j = $j + 1))  with a call
>j=`expr $j + 1`  (which is the extra fork/exec).
>
>>Not very elegant since a limit of 10 iterations is hard-wired.  Can anybody
>>think of a more concise way to do this?  Using PERL is not an option, this
>>must be portable sh code.

deleted second problem


Another solution, involving only one extra fork/exec, is a small C
program to take a command line arg which is the number of iterations
needed and which prints out a character that number of times.  This
would be used in a for loop arg list with backquotes:

  for count in `iter $1`
  do
     process for $1 iterations
  done

I wrote this once but do not have the code to hand, so the following
is from memory and includes no error checking:

   #include <stdio.h>

   main(argc,argv)
   int argc;
   char **argv;
   {
      int count, iterations;

      iterations=atoi(*(argv+1));

      for(count=0; count < iterations; count++)
      {
	 putchar('a');
	 putchar(' ');  /* to separate the characters */
      }
   }

A slightly more complex version was written up in UNIXWorld, Wizard's
Grabbag.  Instead of putting out one character per iteration it
printed the integer with printf, followed by a newline.  I do not
remember the rationale given for using this method.  The mods are
left up to you if you prefer that approach.  I did just compile the
above and it works as advertised.

Note that the for loop variable will not contain anything of value,
it is just a method for looping a specific number of times.

Bob McGowan  (standard disclaimer, these are my own ...)
Product Support, Wyse Technology, San Jose, CA
..!uunet!wyse!bob
bob@wyse.com