Explore Bash Variables with Dynamic Names
I'm trying to read from Bash variables for which I know the name suffixes, but I want to iterate over the prefixes.
Below is an example:
var1_name="variable1"
var1_size="2"
var2_name="variable2"
var2_size="3"
vars=(var1 var2)
for v in "${vars[@]}"
do
echo $v_name
echo $v_size
done
and I want the result to look like this:
variable1
2
variable2
3
Can this be done with Bash? I have tried with eval
and associative arrays, but I still cannot find a way to examine an already defined variable.
source to share
Below works for me. You first need to construct a variable and then evaluate it with an exclamation point.
var1_name="variable1"
var1_size="2"
var2_name="variable2"
var2_size="3"
vars=("var1" "var2")
for v in "${vars[@]}"
do
name=${v}_name
size=${v}_size
echo ${!name}
echo ${!size}
done
O / P
variable1
2
variable2
3
source to share
auhuman's helpful answer solves your problem exactly as asked.
Here's an alternative that doesn't require you to first prefix the name in the array, assuming that all variables of interest have names with the same prefix, e.g . var
:
for name in "${!var@}" # Loop over all variables whose names start with 'var'.
do
[[ $name =~ ^var[0-9]+_(name|size)$ ]] || continue # Ignore unrelated names.
echo "${!name}" # Use variable indirection to print the variable value.
done
-
The code uses two forms of Bash's variable indirection , based on the syntax
${!...}
:-
"${!var@}"
is a form of a literal-based list : it expands to a list (array) of names of all defined variables whose names have a literal prefixvar
(names start withvar
), if any. Since before@
only literal is allowed, using a template like"${!var[0-9]_@}"
-
Example:
for varName in "${!HOST@}"; do echo "$varName"; done
givesHOSTNAME
andHOSTTYPE
eg. -
The corresponding syntax
${!var*}
(no double quotes) seems to work the same way.
(Curiously, the pageman
claims that 1st char. Of is$IFS
used to concatenate matching names, which will only work while waiting in a loopfor
if that 1st char. Is a char. Space. (Which is true for the$IFS
default value that starts with space), but in practice a space is always used, regardless of the value$IFS
, with(IFS=@; echo ${!HOST*})
)
-
-
${!name}
, a variable-based scalar form , expands to the value of a variable whose name is stored as a value$name
.-
Example:
var='value'; name='var'; echo ${!name}
givesvalue
. -
Note. When using a trick (not used above), you can use an indirect expression for to get the values of an array , namely by adding the all-indices
[@]
to the variable name to reference it indirectly; eg .:arr=( one two three ); name='arr[@]'; echo "${!name}"
givesone two three
; accessing a specific element this way (for examplename='arr[1]'
) also works, but retrieving a range of elements does not (for examplename='arr[@]: 0:2'
-
-
There is also a form of array indices list - not used above - which expands to a list (array) of indices / keys of a given array / associative array.
-
Example:
arr=( one two three ); echo "${!arr[@]}"
gives0 1 2
, implicit sequential array indices. -
It works similarly to explicitly assigned indices (for example
arr=( [10]=one two three ); echo "${!arr[@]}"
) or, in Bash v4 +, with associative arrays (although, like the nature of associative arrays, keys cannot be listed in the order they were defined; for exampledeclare -A aarr=( [one]=1 [two]=2 ); echo "${!aarr[@]}"
).
-
-
-
[[ $v =~ ^var[0-9]+_(name|size)$ ]]
uses an operator=~
to match a variable name with an extended regex in RHS to determine if it's an interesting name.
source to share