How do I iterate over a range of numbers defined by variables in Bash?

How do I iterate over a range of numbers in Bash when the range is given by a variable?

I know I can do this (called "sequence expression" in the Bash documentation):

 for i in {1..5}; do echo $i; done

Which gives:

1
2
3
4
5

Yet, how can I replace either of the range endpoints with a variable? This doesn't work:

END=5
for i in {1..$END}; do echo $i; done

Which prints:

{1..5}


for i in $(seq 1 $END); do echo $i; done

编辑:我更喜欢seq在其他方法,因为我实际上可以记住它;)


The seq method is the simplest, but Bash has built-in arithmetic evaluation.

END=5
for ((i=1;i<=END;i++)); do
    echo $i
done
# ==> outputs 1 2 3 4 5 on separate lines

The for ((expr1;expr2;expr3)); construct works just like for (expr1;expr2;expr3) in C and similar languages, and like other ((expr)) cases, Bash treats them as arithmetic.


discussion

Using seq is fine, as Jiaaro suggested. Pax Diablo suggested a Bash loop to avoid calling a subprocess, with the additional advantage of being more memory friendly if $END is too large. Zathrus spotted a typical bug in the loop implementation, and also hinted that since i is a text variable, continuous conversions to-and-fro numbers are performed with an associated slow-down.

integer arithmetic

This is an improved version of the Bash loop:

typeset -i i END
let END=5 i=1
while ((i<=END)); do
    echo $i
    …
    let i++
done

If the only thing that we want is the echo , then we could write echo $((i++)) .

ephemient taught me something: Bash allows for ((expr;expr;expr)) constructs. Since I've never read the whole man page for Bash (like I've done with the Korn shell ( ksh ) man page, and that was a long time ago), I missed that.

So,

typeset -i i END # Let's be explicit
for ((i=1;i<=END;++i)); do echo $i; done

seems to be the most memory-efficient way (it won't be necessary to allocate memory to consume seq 's output, which could be a problem if END is very large), although probably not the “fastest”.

the initial question

eschercycle noted that the {a..b} Bash notation works only with literals; true, accordingly to the Bash manual. One can overcome this obstacle with a single (internal) fork() without an exec() (as is the case with calling seq , which being another image requires a fork+exec):

for i in $(eval echo "{1..$END}"); do

Both eval and echo are Bash builtins, but a fork() is required for the command substitution (the $(…) construct).

链接地址: http://www.djcxy.com/p/17460.html

上一篇: 线Bash无限while循环

下一篇: 如何遍历Bash中由变量定义的一系列数字?