我们知道在shell脚本中,可以通过{x..y}
这样的表达式来表示一个从x到y的数列
echo {1..10}
1 2 3 4 5 6 7 8 9 10
这个用法在shell脚本里叫做Brace Expansion
。
因此我们常利用这个表达式来作为循环的次数,如:
for i in {1..10}
do
echo "$i"
done
可以得到从1到10的输出结果。
但是如果我们想输出从1到一个变量的结果,这个变量从其他地方获取:
NUM=10
for i in {1..$NUM}
do
echo "$i"
done
得到的结果却是
{1..10}
先说解决方案
放弃使用{x..y}
这样的表达式:
NUM=10
for i in $(seq 1 $NUM)
do
echo "$i"
done
原理
seq
命令的原理就不说了,这里说说为什么不能在{ }
中使用变量。其实原因写在bash的man手册中:
Brace expansion is performed before any other expansions, and any characters special to other expansions are preserved in the result. It is strictly textual. Bash does not apply any syntactic interpretation to the context of the expansion or the text between the braces.
大意是说,Bash中会最先展开{ }
中的内容,这个时候$NUM
还不会被具体的值替代,所以是i
在循环中读取的是‘{1..$NUM}’
的一个完整的字符串,输出时$NUM
会被10替代,就有了'{1..10}'
这样的结果。
关于Bash中的展开 (expansion) 顺序,其实有不少值得注意的地方,一不留神可能就会踩坑,还是老前辈那句:脚本猛于虎。