Indirect Variable Reference
Do you know that both bash and ksh support indirect variable reference (though in different ways)? Compared with "eval", this is clearer and conciser. Let me illustrate this using an example.
Suppose we have two variables var1
and var2
. And, there is also a variable
ref
which refers to either var1
or var2
. However, the value of ref
is
decided at run time.
var1="foo bar" var2="hello world" # ..., after some calculation, we got this: ref="var2"
To get the intended value (i.e. "hello world" in this example), the "eval" way could be some like this:
value=$(eval "echo \$$ref") # value: hello world
For bash, this code can be simplified using ${!ref}
value=${!ref} # value: hello world
In contrast, in ksh we define a "name reference" using nameref ref
.
$ var1="foo bar" $ var2="hello world" $ nameref ref=var2 $ echo $ref hello world
Indirect reference to BASH arrays
arr=(a b c d) array_name=arr ref_to_array=${array_name}[@] # i.e. ref_to_array=arr[@] for each in "${!ref_to_array}"; do echo $each; done ref_to_second_elem=${array_name}[1] echo ${!ref_to_second_elem}
KSH Caveats
Although it provids some convenience, the name reference mechanism in KSH can be tricky. One have to be very clear about what is changing, the reference itself or the referred variable? Here are some examples illustrating some subtle details.
$ read ref # change the value of var2 oops $ echo $ref oops $ echo $var2 oops $ ref=var1 # change the value of var2 $ echo $ref var1 $ echo $var2 var1 $ unset -n ref # unset the name reference $ ref=var2 # assign value to ref, which is a normal var so far $ echo $ref var2 $ nameref ref # making it a reference $ echo $ref hello world $ unset -n ref $ var2="hello world" $ nameref ref # declare a name reference $ ref=var2 # the first assignment changes reference itself $ echo $ref hello world $ ref=var1 # the second assignment changes the value of referred variable $ echo $ref var1 $ echo $var2 var1 $ ksh --version version sh (AT&T Research) 93u+ 2012-08-01 $ unset -n ref $ read ref # declare nameref AFTER read, works var2 $ echo $ref var2 $ nameref ref $ echo $ref hello world $ unset -n ref # declare nameref BEFORE read, oops $ nameref ref $ read ref var2 $ echo $ref Segmentation fault (core dumped)
blog comments powered by Disqus