协慌网

登录 贡献 社区

如何迭代 Bash 中变量定义的一系列数字?

当变量给出范围时,如何在 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

evalecho都是 Bash 内置eval ,但命令替换需要fork()$(…)构造)。