Bash – Shell variables in a for loop

bashforvariable

I have a difficulty getting over this man bash passage.

                          If the control variable in a for loop has the
nameref attribute, the list of words can be a list of shell  variables,
and  a name reference will be established for each word in the list, in
turn, when the loop is executed.  Array variables cannot be  given  the
-n attribute.  However, nameref variables can reference array variables
and subscripted array variables.

Could you give an example of this nameref variable in a loop with some explanation?

Best Answer

A nameref variable is to a “normal” variable what a symbolic link is to a regular file.

$ typeset -n ref=actual; ref=foo; echo "$actual"
foo

A for loop executes the body with the loop variable (the “control variable”) bound in turn to each word in the list.

$ for x in one two three; do echo "$x"; done
one
two
three

This is equivalent to writing out successive assignments:

x=one; echo "$x"
x=two; echo "$x"
x=three; echo "$x"

If the loop variable is a nameref, then the body is executed with the nameref targeting each element of the word list in turn. This is not equivalent to a series of assignment like above: an assignment ref=value where ref is a nameref would affect the variable that ref is pointing to, but the for loop changes where the nameref points rather than following the reference to change the variable that it points to.

$ original=0; one=1; two=2; three=3
$ typeset -n ref=original
$ echo $ref
0
$ for ref in one two three; do echo "$ref"; done
1
2
3
$ echo original
0

The indirection can be observed through assignments as well, if you assign to the loop variable (which is uncommon, but permitted).

$ one=1; two=2; three=3
$ typeset -n ref
$ for ref in one two three; do echo ref=$((ref+10)); done
$ echo "$one $two $three"
11 12 13

The last sentence explains that the target of a nameref can be an array. The nameref itself isn't an array, it's still a scalar variable, but when it's used in an assignment or in a dereference, it acts as the same type as the variable it points to.

$ a=(0 1 2)
$ typeset -n ref=a
$ ref[1]=changed
$ echo "${a[@]}"
0 changed 2