问题
I'm trying to read from Bash variables for which I know name suffixes, but I want to iterate through the prefixes.
I give an example below:
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'd want the output to look like follows:
variable1
2
variable2
3
Is there any to do this with Bash?
I have tried with eval
and associative arrays, but I still can't find a way to examine an already defined variable.
回答1:
Below works for me. You need to construct the variable first and then evaluate it using exclamation.
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
回答2:
auhuman's helpful answer solves your problem exactly as asked.
Here's an alternative that doesn't require you to specify the name prefixes in an array first, assuming that all variables of interest have names with the same prefix, such as 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's value.
done
The code uses two forms of Bash variable indirection, all based on syntax
${!...}
:"${!var@}"
is the literal-based list form: it expands to the list (array) of the names of all defined variables whose names have literal prefixvar
(whose names start withvar
), if any. Since only a literal is allowed to precede@
, using a pattern such asfor more sophisticated matching does not work, unfortunately."${!var[0-9]_@}"
Example:
for varName in "${!HOST@}"; do echo "$varName"; done
yieldsHOSTNAME
andHOSTTYPE
, for instance.The related
${!var*}
syntax (without double quotes) seems to work the same.
(Curiously, theman
page claims that the 1st char. of the$IFS
value is used to concatenate the matching names, which would only work as expected in afor
loop if that 1st char. is a whitespace char. (which is true of the$IFS
default value, which starts with a space), but in practice a space is always used, irrespective of the value of$IFS
; verify with(IFS=@; echo ${!HOST*})
)
${!name}
, the variable-based scalar form, expands to the value of the variable whose name is stored as the value of$name
.Example:
var='value'; name='var'; echo ${!name}
yieldsvalue
.Note: With a trick (not used above), you can use indirection to get an array's values too, namely by appending the all-indices index expression
[@]
to the name of the variable to reference indirectly; e.g.:arr=( one two three ); name='arr[@]'; echo "${!name}"
yieldsone two three
; accessing a specific element this way (e.g.,name='arr[1]'
) works too, but extracting a range of elements does not (e.g.,).name='arr[@]: 0:2'
There is also an array-index list form - not used above - which expands to the list (array) of indices / keys of a given array / associative array.
Example:
arr=( one two three ); echo "${!arr[@]}"
yields0 1 2
, the implicit sequential indices of the array.It works analogously with explicitly assigned indices (e.g.,
arr=( [10]=one two three ); echo "${!arr[@]}"
) or, in Bash v4+, with associative arrays (although, as is the nature of associative arrays, the keys are not guaranteed to be listed in the order they were defined; e.g.,declare -A aarr=( [one]=1 [two]=2 ); echo "${!aarr[@]}"
).
[[ $v =~ ^var[0-9]+_(name|size)$ ]]
uses the=~
operator to match the variable name at hand against the extended regular expression on the RHS to determine if it is a name of interest.
来源:https://stackoverflow.com/questions/43306880/examine-bash-variables-with-dynamic-names