1

I am new to Unix shell scripting My code is as follows:

  i=0
for var in 'a' 'b' 'c' 'd' 'e'
do
  content[i]=var
  ((i=`expr i+1`))
done
a=10
b=50
c=40
d=90
e=100
Now I wanted to print the local variables contents using array into the function

print_array
{
echo "${content[0]}"
echo "${content[1]}"
echo "${content[2]}"
echo "${content[3]}"
echo "${content[4]}"
} 

what I wanted to do that array contents are {a,b,c,d,e} and there is a local variables named a,b,c,d,e with some assigned values I wanted to print those local variables through the use of array since the name of array element and local variable element is same so I tried to call by reference by trying multiple combinations of $ and array_names but not working

Aman
  • 1,201

3 Answers3

1

Try

#i=0
for var in 'a' 'b' 'c' 'd' 'e'
do
  content[${#content[*]}]=$var  # or content[i++]=$var
done
# or just content=( 'a' 'b' 'c' 'd' 'e' )
a=10
b=50
c=40
d=90
e=100
for i in "${#content[@]}"
do
  echo ${!i}
done
Costas
  • 14,916
1

So I'll define an indirect printing function first...

_print() while [ "$#" -ne 0 ]
         do    printf '$%s = %d\n' \
                       "$1" "$(($1))"
               shift
         done

Next I'll setup the array and increment...

arr=( a b c d e ); i=0
for var in "${arr[@]}"
do  : "$(($var=(i+=10)))"
done

So now the value of $a is 10 and $b 20 and so on. Last there remains only to print...

_print "${arr[@]}"

...which prints to stdout...

$a = 10
$b = 20
$c = 30
$d = 40
$e = 50

All of this works because of the way the shell handles $((math)) expansions - they're basically evals. In an arithmetic expansion the shell first expands any other valid shell expansion before attempting to do the math - making the actual math its last order of business.

This means that if you do:

i=a a=10; echo "$(($i))" 

The printed result is 10 because the shell expands the value of $i to get a then evaluates that result as an integer reference.

The above will work in any POSIX-compliant shell.

This means I could possibly also have done...

i=10
for var in a b c d e
do  arr[($var=i*${#arr[@]}+i)/i]=$var
done

...to handle array assignment, index evaluation, and $var integer assignment at once because the [index] brackets of a named shell array - in a shell which supports them - are treated identically to the $((expansion)) parens of a math expression.

Running the above code wrapped in ksh -xc command prints the following debug output to standard error:

+ arr[1]=a
+ arr[2]=b
+ arr[3]=c
+ arr[4]=d
+ arr[5]=e

From there I can just do:

echo "$((${arr[1]}))"
echo "$((a))"

...to print...

10
10

...because they evaluate to the same thing in shells which support named arrays. However, in shells which don't...

echo 'arr=(a b c d e)' | bash -x
+ arr=(a b c d e)     #bash traces the successful command to stderr
echo 'arr=(a b c d e)' | sh -x
sh: 1: Syntax error: "(" unexpected   #sh traces something else

So in the _print() function I just shift over the positional parameters (which represents a truly portable shell "$@"array) while there are any at all and printf...

  1. First a $ dollar sign.
  2. Then the %string value stored in my $1st positional parameter.
  3. Then an = equals sign.
  4. And last the value stored in the value stored in my $(($1)) first positional parameter.

As the function shifts its arguments away the first positional parameter is constantly being replaced with the next until the $# count of positionals equals 0 and the function returns.

Before running the function when I initialize the array and its constituent indirection variables that works like this:

  • for var in "${arr[@]}"

    • The shell will expand [@] to a list of arguments and [*] to a single concatenation of that list. If the expansion is not quoted it might also expand [*] out to a list as well - depending on whether or not there is a value for $IFS when it is done and how set -filename expansion is currently configured - but if it does so it likely does not do it the way you intend.
  • : "$(($var=(i+=10)))"

    • Each value in ${arr[@]} is assigned to the value of $var in turn. $(($var=(i+=10))) is then expanded first for the value in $var like $((a=(i+=10))) and last of all the math is done - which first increments $i by 10 and next assigns the value of $i to $a.
mikeserv
  • 58,310
  • @mikerserv It is giving error 0403-057 Syntax error at line 6 : `(' is not expected. means at this line arr=( a b c d e ); i=0 then I have changed it to arr= 'a' 'b' 'c' 'd' 'e' then error message a: not found is coming please guide me to solve it thanks a lot for your descriptive answer :) – Aman Apr 07 '15 at 11:13
  • @Aman - a: not found sounds like you're trying to run a command. Which version of ksh? – mikeserv Apr 07 '15 at 11:49
  • I am running on bash 4.2 – Aman Apr 07 '15 at 13:28
  • @Aman - well, then you must have entered something in wrong - everything up there works in bash - at least it does on my system. Have you tried it since edited it? It shouldn't make a difference though... – mikeserv Apr 07 '15 at 14:15
  • I am going to retest it. – Aman Apr 07 '15 at 14:19
  • -bash-4.2$ cat >lastexp.ksh _print() while [ "$#" -ne 0 ] do printf '$%s = %d\n'
    "$1" "$(($1))" shift done arr=( a b c d e ); i=0 for var in "${arr[@]}" do : "$(($var=(i+=10)))" done _print "${arr[@]}"
    ^C -bash-4.2$ sh lastexp.ksh lastexp.ksh[6]: 0403-057 Syntax error at line 6 : `(' is not expected.
    – Aman Apr 07 '15 at 14:21
  • @Aman - you're trying to enter it all in on one line? And what is lastexp.ksh? You can't do that. Where there are line breaks in the command examples you need line breaks - either that or semi-colons. If you want to do it at the terminal prompt you can, but enter it in by line as it is presented. I guess I could make a copy/paste version for you if you want. A tip, by the way - to enter a \newline at your prompt you can probably use CTRL+V then CTRL+J. Your error though is due to the function and array definition running together - it would need to be done; arr=( at that point, – mikeserv Apr 07 '15 at 14:27
  • @Aman - here is that command all on a single line, if you really want it that way: _print() while [ "$#" -ne 0 ]; do printf '$%s = %d\n' "$1" "$(($1))"; shift; done;arr=( a b c d e ); i=0;for var in "${arr[@]}";do : "$(($var=(i+=10)))";done;_print "${arr[@]}"; Maybe also try: i=25; for var in a b c d e; do arr[($var=i*${#arr[@]}+i)/i]=$var; done and afterward running _print "${arr[@]}" again - the results are the same, except that you can put different numbers in i and it will increment automatically. So i=3 will increment each assigned $var by three as they are assigned. – mikeserv Apr 07 '15 at 14:42
  • again not working -bash-4.2$ cat > testksh.ksh _print() while [ "$#" -ne 0 ]; do printf '$%s = %d\n' "$1" "$(($1))"; shift; done;arr=( a b c d e ); i=0;for var in "${arr[@]}";do : "$(($var=(i+=10)))";done;_print "${arr[@]}"; ^C -bash-4.2$ sh testksh.ksh testksh.ksh: 0403-057 Syntax error at line 1 : `(' is not expected. – Aman Apr 07 '15 at 15:33
  • @Aman Oh, yeah, of course not. You're invoking sh - not bash. While it's possible the two share the same executable (which is true of some systems) bash doesn't do arrays when invoked as sh because it goes into POSIX conformance mode. You won't have any luck with this at all that way. And what is this testksh.ksh stuff? Anyway, there are arrays (of my own preferred) in POSIX-mode - but those are the positional arrays which are created one per function - (I use one above when working with $1) but that's a different thing than named arrays. There's no - arr[index]= either. – mikeserv Apr 07 '15 at 15:39
  • @Aman - see the edit I made here and maybe see here. – mikeserv Apr 07 '15 at 16:02
1

If I understand you correctly you want an indirection in variable's access with, e.g., bash. With this code:

content=( a b c d e )

a=10
b=50
c=40
d=90
e=100

echo "${!content[0]}"
echo "${!content[1]}"
echo "${!content[2]}"
echo "${!content[3]}"
echo "${!content[4]}"

You will get this result:

10
50
40
90
100

The key here is bash's specific variable expansion access method "${! ... }".

Janis
  • 14,222
  • I have bash 4.2 which does not support echo "${!content[4]}" mentioned process substitution please guide me :) – Aman Apr 07 '15 at 17:43
  • @Aman; the construct that I proposed is certainly running even in old bash versions. In every proposed solution you claim you are running a bash and getting errors. So I have to say I have my doubts that what you say is true! - Try two things: bash --version, and (instead of calling your script as ./yourscript) call your script explicitly with bash yourscript. – Janis Apr 08 '15 at 06:31
  • @Aman; I just see in an analysis of another poster's answer that you are running sh and not bash. So use the form I proposed to call your script, bash yourscript, and everything should work fine. – Janis Apr 08 '15 at 06:38