当范围由变量给定时,如何在Bash中迭代一系列数字?
我知道我可以做到这一点(在Bash文档中称为“序列表达式”):
for i in {1..5}; do echo $i; done
这给出了:
1.2.3.4.5.
然而,如何用变量替换任意一个范围端点?这不起作用:
END=5
for i in {1..$END}; do echo $i; done
哪些打印:
{1..5}
当范围由变量给定时,如何在Bash中迭代一系列数字?
我知道我可以做到这一点(在Bash文档中称为“序列表达式”):
for i in {1..5}; do echo $i; done
这给出了:
1.2.3.4.5.
然而,如何用变量替换任意一个范围端点?这不起作用:
END=5
for i in {1..$END}; do echo $i; done
哪些打印:
{1..5}
当前回答
您可以使用
for i in $(seq $END); do echo $i; done
其他回答
如果你需要前缀,你可能会喜欢这个
for ((i=7;i<=12;i++)); do echo `printf "%2.0d\n" $i |sed "s/ /0/"`;done
这将产生
07
08
09
10
11
12
POSIX方式
如果您关心可移植性,请使用POSIX标准中的示例:
i=2
end=5
while [ $i -le $end ]; do
echo $i
i=$(($i+1))
done
输出:
2
3
4
5
非POSIX的事物:
(())没有美元,尽管它是POSIX本身提到的常见扩展。[[.]在这里就足够了。另请参见:Bash中的单方括号和双方括号之间的区别是什么?用于((;;))seq(GNU内核){start..end},并且无法使用Bash手册中提到的变量。设i=i+1:POSIX 7 2。Shell命令语言不包含单词let,并且在bash上失败--posix 4.3.42i=$i+1的美元可能是必需的,但我不确定。POSIX 7 2.6.4算术扩展表示:如果外壳变量x包含形成有效整数常量的值,可选地包括前导加号或减号,则算术展开式“$((x))”和“$($x)”应返回相同的值。但从字面上看,这并不意味着$((x+1))会膨胀,因为x+1不是一个变量。
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将它们视为算术。
这是另一种方式:
end=5
for i in $(bash -c "echo {1..${end}}"); do echo $i; done
讨论
正如加亚罗所建议的那样,使用seq是可以的。Pax Diablo建议使用Bash循环来避免调用子进程,如果$END太大,则具有更友好内存的额外优势。Zathur发现了循环实现中的一个典型错误,并暗示,由于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允许((expr;expr;expr))构造。由于我从未阅读过Bash的整个手册页(就像我很久以前在Kornshell(ksh)手册页上所做的那样),所以我错过了这一点。
So,
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手册,这是正确的。可以用一个单独的(内部)fork()而不使用exec()来克服这个障碍(就像调用seq一样,这是另一个映像,需要fork+exec):
for i in $(eval echo "{1..$END}"); do
eval和echo都是Bash内置的,但是命令替换($(…)构造)需要一个fork()。