当变量给出范围时,如何在 Bash 中迭代一系列数字?
我知道我可以这样做(在 Bash 文档中称为 “序列表达式”):
for i in {1..5}; do echo $i; done
这使:
1
2
3
4
五
但是,如何用变量替换任何一个范围端点?这不起作用:
END=5
for i in {1..$END}; do echo $i; done
哪个印刷品:
{} 1..5
for i in $(seq 1 $END); do echo $i; done
编辑:我更喜欢seq
而不是其他方法,因为我实际上可以记住它;)
seq
方法是最简单的,但 Bash 具有内置的算术评估。
END=5
for ((i=1;i<=END;i++)); do
echo $i
done
# ==> outputs 1 2 3 4 5 on separate lines
for ((expr1;expr2;expr3));
构造就像在 C 和类似语言中的for (expr1;expr2;expr3)
一样工作,和其他((expr))
情况一样,Bash 将它们视为算术。
正如加罗所说,使用seq
很好。 Pax Diablo 建议使用 Bash 循环来避免调用子进程,如果 $ END 太大,还有额外的优点:更友好。 Zathrus 在循环实现中发现了一个典型的错误,并且还暗示由于i
是一个文本变量,因此连续的转换往返数字会以相关的减速执行。
这是 Bash 循环的改进版本:
typeset -i i END
let END=5 i=1
while ((i<=END)); do
echo $i
…
let i++
done
如果我们想要的唯一东西就是echo
,那么我们可以写echo $((i++))
。
ephemient教我一些东西:Bash 允许for ((expr;expr;expr))
构造。因为我从来没有读过 Bash 的整个手册页(就像我使用 Korn shell( ksh
)手册页那样,那是很久以前的事了),我错过了。
所以,
typeset -i i END # Let's be explicit
for ((i=1;i<=END;++i)); do echo $i; done
似乎是最节省内存的方式(没有必要分配内存来消耗seq
的输出,这可能是一个问题,如果 END 非常大),虽然可能不是 “最快”。
eschercycle 注意到 { a .. b } Bash 表示法仅适用于文字; 是的,相应于 Bash 手册。可以使用没有exec()
的单个(内部) fork()
来克服这个障碍(就像调用seq
的情况一样,这是另一个图像需要 fork + exec):
for i in $(eval echo "{1..$END}"); do
eval
和echo
都是 Bash 内置eval
,但命令替换需要fork()
( $(…)
构造)。