我正在努力习惯shell脚本并遇到一个我觉得有趣且无法解释的行为。在下面的代码中,第一个for循环将正确执行,但第二个不会。
declare letters=(a b c d e f g)
for i in {0..7}; do
echo ${letters[i]}
done
for i in {0..${#letters[*]}}; do
echo ${letters[i]}
done
第二个for循环导致以下错误:
syntax error: operand expected (error token is "{0..7}")
让我感到困惑的是,${#letters[*]}
显然正确地被评估为数字7.但尽管如此,即使我们看到与{0..7}
相同的循环完全正常,代码也会失败。
这是什么原因?
我正在运行OS X 10.12.2,GNU bash版本3.2.57。
答案 0 :(得分:5)
括号扩展在参数扩展之前发生(请参阅man bash
中的扩展),因此它仅适用于文字。换句话说,你不能对变量使用大括号扩展。
您可以使用C风格的循环:
for ((i=0; i<${#letters[@]}; i++)) ; do
echo ${letters[i]}
done
或seq
之类的外部命令:
for i in $(seq 1 ${#letters[@]}) ; do
echo ${letters[i-1]}
done
但是你通常不需要索引,而是在元素本身上循环,请参阅下面的@ TomFenech的答案。他还展示了另一种获取指数列表的方法。
请注意,它应为{0..6}
,而不是7
。
答案 1 :(得分:3)
支撑扩展在参数扩展之前发生,因此您不能将变量用作范围的一部分。
将数组展开为值列表:
for letter in "${letters[@]}"; do
echo "$letter"
done
或者,将数组的索引扩展为列表:
for i in ${!letters[@]}; do
echo "${letters[i]}"
done
正如评论中所提到的(感谢),这两种方法也适用于稀疏数组;您不能总是假设数组为0
和${#letters[@]}
之间的每个索引定义一个值。