[comp.unix.wizards] Building Variable Names in Bourne Shell

kevinc@bearcat.lim.tek.com (Kevin Cosgrove 627-5212) (03/22/88)

Anyone know how to build *accessible* variable names on the fly in Bourne
shell?  Below is a do nothing script which, I hope, demonstrates what I
want to do.

#!/bin/sh
onestring="A"			# set the values of arbitrary strings
twostring="B"
threestring="C"
for string in one two three	# loop thru string sets
do
   var="${string}string"	# var contains the name of the string
				# I wish to get access to

   echo "\$$var = ${var}"	# how do I get the contents of the string
				# "pointed to" by var?
   echo
done

Yes, I know there are lots of other shells and/or languages which make
the above easy to do, but I'm trying to patch existing scripts, and this
would make it much easier to do.


Disclaimer:  donning fire resistant suit now...
__________________________________________________________________________

	Kevin Cosgrove			Tektronix, Inc.
	(503)-627-5212			PO Box 500, M/S 47-092
	kevinc@bearcat.LIM.TEK.COM	Beaverton, OR  97077
__________________________________________________________________________

ron@topaz.rutgers.edu (Ron Natalie) (03/23/88)

Try eval...

onestring="A"			# set the values of arbitrary strings
twostring="B"
threestring="C"
for string in one two three	# loop thru string sets
do
   var="${string}string"	# var contains the name of the string
				# I wish to get access to

     echo \$$var=`eval echo \\$$var`


done
 

mtr@eagle.ukc.ac.uk (M.T.Russell) (03/24/88)

In article <12565@brl-adm.ARPA> kevinc@bearcat.lim.tek.com (Kevin Cosgrove 627-5212) writes:
>Anyone know how to build *accessible* variable names on the fly in Bourne
>shell?

One method is to echo appropriate magic to a file, and then source
that file.  Thus the following Bourne shell fragment

	fred="hello world"
	varname=fred
	echo result=\$$varname > tmpfile
	. tmpfile

sets the variable result to $fred, or "hello world" in this case.

By the way, I find the "." command very useful in shell scripts.
Arguably it's better than shell functions because you get named
parameters - you can do things like

	question="Do you want to load all the software"
	default=yes
	. ask		# ask is a neat script for asking questions
	if [ "$answer" = yes ]; then
		...

where the shell variables question and default are effectively 
parameters to the ask script, and answer is the return value.
You have to be disciplined with variable names though, as all
variables are of course global.

Mark Russell
mtr@ukc.ac.uk

alen@cogen.UUCP (Alen Shapiro) (03/24/88)

In article <12565@brl-adm.ARPA> kevinc@bearcat.lim.tek.com (Kevin Cosgrove 627-5212) writes:
>Anyone know how to build *accessible* variable names on the fly in Bourne
>shell?  Below is a do nothing script which, I hope, demonstrates what I
>want to do.
>
>#!/bin/sh
>onestring="A"			# set the values of arbitrary strings
>twostring="B"
>threestring="C"
>for string in one two three	# loop thru string sets
>do
>   var="${string}string"	# var contains the name of the string
>				# I wish to get access to
>
>   echo "\$$var = ${var}"	# how do I get the contents of the string
>				# "pointed to" by var?
>   echo
>done
>
>Yes, I know there are lots of other shells and/or languages which make
>the above easy to do, but I'm trying to patch existing scripts, and this
>would make it much easier to do.


Nice exercise - try this. BTW /bin/calendar is a GREAT crib sheet for 
such things 
 
#!/bin/sh 
onestring="A"
twostring="B"
threestring="C"
for string in one two three
do
    var="a=\$${string}string"
    eval $var
    echo ${string}string = $a
done
 
--alen the Lisa slayer (it's a long story)

In
te
re
st
in
g
li
ne
fi
ll
er
go
es
he
re

alan@ecrcvax.UUCP (Alan P. Sexton) (03/24/88)

In article <12565@brl-adm.ARPA> kevinc@bearcat.lim.tek.com (Kevin Cosgrove 627-5212) writes:
>Anyone know how to build *accessible* variable names on the fly in Bourne
>shell?  Below is a do nothing script which, I hope, demonstrates what I
>want to do.
>
>#!/bin/sh
>onestring="A"			# set the values of arbitrary strings
>twostring="B"
>threestring="C"
>for string in one two three	# loop thru string sets
>do
>   var="${string}string"	# var contains the name of the string
>				# I wish to get access to
>
>   echo "\$$var = ${var}"	# how do I get the contents of the string
>				# "pointed to" by var?
>   echo
>done

Here is an example that I think will show how to do what you want.
I wrote it a looooong time ago to learn how to do shell
programming and kept it as a reference.
I make no claim that it is a `good' example of a sh script - merely
that it shows how to pretend that sh has dynamic array variables and the
like.

The script records a persons name, the number of hours of lectures and the
number of hours of tutorials he has given. It is very stupid and it
would be far easier to just edit a file to record the data.
a script of a sample is included.

I originally wrote this on a version 7 system (yes THAT long ago)
and I just fixed it so that it works on a bsd4.3 system so that I
could get the typescript.

Alan Sexton				ECRC, Arabellastr 17,
alan@ecrcvax.UUCP			8000 Muenchen 81, West Germany
mcvax!unido!ecrcvax!alan		tel. (089) 92699164

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	paycheck
#	typescript
# This archive created: Thu Mar 24 12:28:57 1988
export PATH; PATH=/bin:$PATH
echo shar: extracting "'paycheck'" '(1874 characters)'
if test -f 'paycheck'
then
	echo shar: will not over-write existing file "'paycheck'"
else
sed 's/^X//' << \SHAR_EOF > 'paycheck'
X#! /bin/sh
XN=1
Xif test -f "$1"
Xthen
X   exec <$1
X   while read NAME$N LECTS$N TUT$N
X   do
X      eval echo $"NAME$N" \\\	 $"LECTS$N" \\\	 $"TUT$N"
X      N=`expr $N + 1`
X   done
X   exec 0<&2
Xfi
XNUMBER=`expr $N - 1`
Xwhile true
Xdo
X   while true
X   do
X      echo -n "Name: "
X      if read name
X      then
X         N=1
X         while eval test $N -le $NUMBER -a \"$"NAME$N"\" != \""$name"\"
X         do
X            N=`expr $N + 1`
X         done
X         if test $N -gt $NUMBER
X         then
X            echo -n "New Lecturer? : "
X            read ANS
X            until test "$ANS" = "y" -o "$ANS" = "n"
X            do
X               echo -n "New Lecturer [y/n]? : "
X               read ANS
X            done
X            if test "$ANS" = "y"
X            then
X               eval NAME$N=$name
X               eval LECTS$N=0
X               eval TUT$N=0
X               NUMBER=$N
X            else
X               break
X            fi
X         fi
X         echo Name \	 Lects. \	 Tuts.
X         eval echo $"NAME$N" \\\	$"LECTS$N" \\\	 $"TUT$N"
X         echo -n "Number of Lectures ? : "
X         read LECTS$N
X         echo -n "Number of Tutorials ? : "
X         read TUT$N
X         echo Name \	 Lects. \	 Tuts.
X         eval echo $"NAME$N" \\\	 $"LECTS$N" \\\	 $"TUT$N"
X      fi
X      ANS=
X      echo -n "Finished ? : "
X      read ANS
X      until test "$ANS" = "y" -o "$ANS" = "n"
X      do
X         echo -n "Finished [y/n] ? : "
X         read ANS
X      done
X      if test "$ANS" = "n"
X      then
X         break
X      else
X         break 2
X      fi
X   done
Xdone
XN=1
Xwhile test $N -le $NUMBER
Xdo
X   eval echo $"NAME$N" \\\	 $"LECTS$N" \\\	 $"TUT$N"
X   N=`expr $N + 1`
Xdone
Xecho 'output file name (<EOT> to quit with no output) : '
Xread file || ( echo "no  output" ; exit 1 )
Xexec >$file
XN=1
Xwhile test $N -le $NUMBER
Xdo
X   eval echo $"NAME$N"\\\	$"LECTS$N"\\\	$"TUT$N"
X   N=`expr $N + 1`
Xdone
SHAR_EOF
if test 1874 -ne "`wc -c < 'paycheck'`"
then
	echo shar: error transmitting "'paycheck'" '(should have been 1874 characters)'
fi
chmod +x 'paycheck'
fi # end of overwriting check
echo shar: extracting "'typescript'" '(1025 characters)'
if test -f 'typescript'
then
	echo shar: will not over-write existing file "'typescript'"
else
sed 's/^X//' << \SHAR_EOF > 'typescript'
XScript started on Thu Mar 24 12:23:20 1988
X% paycheck
XName: alan
XNew Lecturer? : y
XName 	 Lects. 	 Tuts.
Xalan 	0 	 0
XNumber of Lectures ? : 2
XNumber of Tutorials ? : 3
XName 	 Lects. 	 Tuts.
Xalan 	 2 	 3
XFinished ? : n
XName: john
XNew Lecturer? : y
XName 	 Lects. 	 Tuts.
Xjohn 	0 	 0
XNumber of Lectures ? : 3
XNumber of Tutorials ? : 4
XName 	 Lects. 	 Tuts.
Xjohn 	 3 	 4
XFinished ? : y
Xalan 	 2 	 3
Xjohn 	 3 	 4
Xoutput file name (<EOT> to quit with no output) : 
Xtst
X% 
X% cat tst
Xalan	2	3
Xjohn	3	4
X% paycheck tst
Xalan 	 2 	 3
Xjohn 	 3 	 4
XName: john
XName 	 Lects. 	 Tuts.
Xjohn 	3 	 4
XNumber of Lectures ? : 4
XNumber of Tutorials ? : 6
XName 	 Lects. 	 Tuts.
Xjohn 	 4 	 6
XFinished ? : n
XName: fred
XNew Lecturer? : y
XName 	 Lects. 	 Tuts.
Xfred 	0 	 0
XNumber of Lectures ? : 1  
XNumber of Tutorials ? : 2
XName 	 Lects. 	 Tuts.
Xfred 	 1 	 2
XFinished ? : y
Xalan 	 2 	 3
Xjohn 	 4 	 6
Xfred 	 1 	 2
Xoutput file name (<EOT> to quit with no output) : 
Xtst
X% cat tst
Xalan	2	3
Xjohn	4	6
Xfred	1	2
X% ^D
Xscript done on Thu Mar 24 12:26:07 1988
SHAR_EOF
echo shar: 2 control characters may be missing from "'typescript'"
if test 1025 -ne "`wc -c < 'typescript'`"
then
	echo shar: error transmitting "'typescript'" '(should have been 1025 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
Alan Sexton				ECRC, Arabellastr 17,
alan@ecrcvax.UUCP			8000 Muenchen 81, West Germany
mcvax!unido!ecrcvax!alan		tel. (089) 92699164

gwyn@brl-smoke.ARPA (Doug Gwyn ) (03/25/88)

In article <12565@brl-adm.ARPA> kevinc@bearcat.lim.tek.com (Kevin Cosgrove 627-5212) writes:
>Anyone know how to build *accessible* variable names on the fly in Bourne
>shell?

Try using the "exec" built-in; it's a lot simpler and more efficient
than most of the other proposals.

erik@naggum.se (Erik Naggum) (03/27/88)

I thought this was obvious for the -wizards, so I sent
kevinc@bearcat.lim.tek.com a private reply.

The right thing to do is _eval_.  No . or exec will do the job very fast.

	var='$'${foo}bar
	eval echo '$var = ' $var

The very purpose of eval is to reevaluate the command line.  (That is,
first evaluate the arguments, then execute them, i.e. evaluate them once
more.)

To everyone of those who have proposed wierd solutions:
Go read "An introduction to the UNIX Shell" by S. R. Bourne.
(Sorry if this offends anyone, but negligence on the part of reading
manuals is what I consider the hallmark of the novice.  Besides, I learn
more and more things from reading the same manuals over and over.)

Yours in hacking (nonpejorative meaning),
Erik Naggum
UUCP  --   erik@naggum.uucp		UNIX is not ``eunuchs'' --  
ARPA  --   enag@ifi.uio.no		in fact it's rather potent
Snail --   Naggum Software; POB 1560 VIKA; OSLO 0118; NORWAY; +47-2-384-400