Bash for循环语法

时间:2017-02-10 15:09:39

标签: bash shell for-loop

我正在努力习惯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。

2 个答案:

答案 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[@]}之间的每个索引定义一个值。