Reputation: 1166
First of all sorry because my english may be not good. I want to use a variable to index an element in an array or use the same variable to index all the elements. For example:
...
var1="1"
var2="*"
array=(one two three for five)
for elem in ${array[$var1]}
do
echo $elem
done
When I use var1 to index in ${array[$var1]} it works correctly, but if I use var2 doesn't work correctly, I get this error:
./ed.sh line XXX *: syntax error: operand expected (error token is "*")
I'm pretty sure that the error is related with the * wildcard expansion, but I didn't find an answer that help me to solve this problem. So, how can I do it?
Upvotes: 7
Views: 4205
Reputation: 44354
I don't recommend this, but for completeness you can get this to work by cheating with the expansion order using eval
:
eval items=\${array[$var2]}
for elem in $items
do
echo $elem
done
There are issues with this. eval
is generally pronounced "evil" because there can be security implications in running code from a variable. There is usually a better way to do the job than using eval
. In this case you should give some thought to the design.
There is also an issue if an element contains embedded whitespace. Add:
array+=('at the end')
After the array declaration and you'll see what I mean.
EDIT: After some deliberation, here is a way to do it without eval
, and it supports embedded spaces or tabs (but not embedded newlines). Pretty it is not:
display_it() {
if [[ $1 = '*' ]]; then
oldIFS="$IFS"
IFS=$'\n'
echo "${array[*]}"
IFS="$oldIFS"
else
echo "${array[$1]}"
fi
}
var1="1"
var2="*"
array=(one two three for five)
array+=('at the end')
while read -r elem
do
echo $elem
done < <(display_it "$var2")
Displays:
one
two
three
for
five
at the end
At the end of the loop you will see process substitution where I call the function display_it
. Each item read is separated by a newline, hence the swapping of the Internal Field Separator (IFS
) in the function.
Upvotes: 1
Reputation: 123450
*
and @
are not considered regular elements in the array. They are not listed when iterating keys, and are not considered when expanding indirectly through index variables.
The bash source code has a function chk_atstar
that checks whether [@]
or [*]
is being used, and you can see that it's done literally and not through any expansion:
else if (valid_array_reference (name, 0))
{
temp1 = mbschr (name, '[');
if (temp1 && temp1[1] == '@' && temp1[2] == ']')
{
If you really want to do this, you can go through variable indirection:
arr=(one two three)
index='*'
var="arr[$index]"
echo "${!var}"
though you may be better off not trying to treat these special array access modes as array elements.
Upvotes: 6