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 eval
s. 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
...
- First a
$
dollar sign.
- Then the
%s
tring value stored in my $1
st positional parameter.
- Then an
=
equals sign.
- And last the value stored in the value stored in my
$(($1))
first positional parameter.
As the function shift
s 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 -f
ilename 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
.
bash -version
? I haveGNU bash 4.3.11
– Costas Apr 07 '15 at 10:00eval j=\$$i;echo $j
(and I correct the code abovevar
-->$var
, so try it again) – Costas Apr 07 '15 at 10:06a=b ; b=5 ; echo ${!a}
and show output here – Costas Apr 07 '15 at 17:48