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 documentatio
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.
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”.
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).