如何使此代码有效?
#!/bin/bash
ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )
for FRUIT in ${!ARRAYNAME[@]}
do
echo ${FRUIT}
done
此代码:
echo ${!ARRAYNAME[0]}
打印 APPLE 。我尝试做类似的事情,但用“[@]”迭代数组。
提前致谢,
答案 0 :(得分:26)
${!ARRAYNAME[@]}
表示“ARRAYNAME
”的索引。正如设置ARRAYNAME
后bash man page中所述,但作为字符串而不是数组,它返回0
。
以下是使用eval
的解决方案。
#!/usr/bin/env bash
ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )
eval array=\( \${${ARRAYNAME}[@]} \)
for fruit in "${array[@]}"; do
echo ${fruit}
done
您最初尝试做的是创建Indirect Reference。这些是在bash版本2中引入的,当试图在shell中实现类似反射的行为时,它们在很大程度上取代了对eval
的需求。
在对数组使用间接引用时,您需要做的是在猜测变量名时包含[@]
:
#!/usr/bin/env bash
ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )
array="${ARRAYNAME}[@]"
for fruit in "${!array}"; do
echo $fruit
done
所有这一切,在这个简单的例子中使用间接引用是一回事,但是,正如Dennis Williamson提供的链接所示,你应该对在真实世界的脚本中使用它们犹豫不决。它们几乎可以保证使您的代码比必要的更令人困惑。通常,您可以使用关联数组获得所需的功能。
答案 1 :(得分:13)
这是一种没有评估的方法。
请参阅此处描述的 Bash技巧#2 : http://mywiki.wooledge.org/BashFAQ/006
似乎在bash 3及以上版本中工作。
#!/bin/bash
ARRAYNAME='FRUITS'
tmp=$ARRAYNAME[@]
FRUITS=( APPLE BANANA ORANGE "STAR FRUIT" )
for FRUIT in "${!tmp}"
do
echo "${FRUIT}"
done
这是一个更现实的例子,展示了如何通过引用函数传递数组:
pretty_print_array () {
local arrayname=$1
local tmp=$arrayname[@]
local array=( "${!tmp}" )
local FS=', ' # Field seperator
local var
# Print each element enclosed in quotes and separated by $FS
printf -v var "\"%s\"$FS" "${array[@]}"
# Chop trailing $FS
var=${var%$FS}
echo "$arrayname=($var)"
}
FRUITS=( APPLE BANANA ORANGE "STAR FRUIT" )
pretty_print_array FRUITS
# prints FRUITS=("APPLE", "BANANA", "ORANGE", "STAR FRUIT")
答案 2 :(得分:3)
eval
执行包含数组元素的代码,即使它们包含例如命令替换。它还通过解释其中的bash元字符来更改数组元素。
避免这些问题的工具是declare
参考,请参阅声明下的man bash
:
-n 为每个名称指定nameref属性,使其成为另一个变量的名称引用。另一个变量由name的值定义。除了使用或更改-n属性本身的名称外,对名称的所有引用,赋值和属性修改都是对名称值引用的变量执行的。 nameref属性不能应用于数组变量。
#!/bin/bash
declare -n ARRAYNAME='FRUITS'
FRUITS=(APPLE BANANA ORANGE "BITTER LEMON")
for FRUIT in "${ARRAYNAME[@]}"
do
echo "${FRUIT}"
done
答案 3 :(得分:2)
这个答案来得太晚了,但是我猜想有比目前为止提出的方法更为简洁的方法(对作者的所有方面表示敬意)。
这是关于使用内置-n
/ declare
bash的local
选项的。 (有关更多信息,请在bash中输入help declare
。
所以我们开始:
ARRAYNAME='FRUITS';
FRUITS=(APPLE BANANA ORANGE);
# This is the critical addition. With help of option `-n` we declare
# variable `fruits` as indirect reference to another variable. Anytime
# we refer to ${fruits} we would actually refer to a variable whose
# name is stored in `fruits` variable:
declare -n fruits="${ARRAYNAME}";
# Here we use ${fruits} as ordinary variable, but in reality it refers
# to `FRUITS` variable:
for FRUIT in ${fruits[@]}; do
echo "${FRUIT}";
done;
结果是:
APPLE
BANANA
ORANGE
答案 4 :(得分:0)
我只是想添加另一个有用的用例。我正在网上搜索一个不同但相关问题的解决方案
ARRAYNAME=( FRUITS VEG )
FRUITS=( APPLE BANANA ORANGE )
VEG=( CARROT CELERY CUCUMBER )
for I in "${ARRAYNAME[@]}"
do
array="${I}[@]"
for fruit in "${!array}"; do
echo $fruit
done
done
答案 5 :(得分:0)
尽管OP问题很简单,但这些答案不会针对最常见的实际用例进行扩展,即包含空格或通配符的数组元素,这些数据元素尚未扩展为文件名。
FRUITS=( APPLE BANANA ORANGE 'not broken' '*.h')
ARRAYNAME=FRUITS
eval ARRAY=\(\${$ARRAYNAME[@]}\)
$ echo "${ARRAY[4]}"
broken
$ echo "${ARRAY[5]}"
config.h
$
这有效:
FRUITS=( APPLE BANANA ORANGE 'not broken' '*.h')
ARRAYNAME=FRUITS
eval ARRAY="(\"\${$ARRAYNAME[@]}\")"
$ echo "${ARRAY[3]}"
not broken
$ echo "${ARRAY[4]}"
*.h
$
就像你应该习惯使用"$@"
而不是$@
一样,总是在( )
内引用数组扩展,除非你想要文件名扩展或知道&#39 ; s数组元素不可能包含空格。
执行此操作:X=("${Y[@]}")
不是这个:X=(${Y[@]})