I have gotten the following to work:

for i in {2..10} do echo "output: $i" done 

It produces a bunch of lines of output: 2, output: 3, so on.

However, trying to run the following:

max=10 for i in {2..$max} do echo "$i" done 

produces the following:

output: {2..10} 

How can I get the compiler to realize it should treat $max as the other end of the array, and not part of a string?

6

11 Answers

Brace expansion, {x..y} is performed before other expansions, so you cannot use that for variable length sequences.

Instead, use the seq 2 $max method as user mob stated.

So, for your example it would be:

max=10 for i in `seq 2 $max` do echo "$i" done 
3

Try the arithmetic-expression version of for:

max=10 for (( i=2; i <= $max; ++i )) do echo "$i" done 

This is available in most versions of bash, and should be Bourne shell (sh) compatible also.

2

Step the loop manually:

 i=0 max=10 while [ $i -lt $max ] do echo "output: $i" true $(( i++ )) done 

If you don’t have to be totally POSIX, you can use the arithmetic for loop:

 max=10 for (( i=0; i &lt max; i++ )); do echo "output: $i"; done 

Or use jot(1) on BSD systems:

 for i in $( jot 0 10 ); do echo "output: $i"; done 
2

If the seq command available on your system:

for i in `seq 2 $max` do echo "output: $i" done 

If not, then use poor man's seq with perl:

seq=`perl -e "\$,=' ';print 2..$max"` for i in $seq do echo "output: $i" done 

Watch those quote marks.

0

We can iterate loop like as C programming.

#!/bin/bash for ((i=1; i<=20; i=i+1)) do echo $i done 

There's more than one way to do it.

max=10 for i in `eval "echo {2..$max}"` do echo "$i" done 
2

This is a way:
Bash:

max=10 for i in $(bash -c "echo {2..${max}}"); do echo $i; done 

The above Bash way will work for ksh and zsh too, when bash -c is replaced with ksh -c or zsh -c respectively.

Note: for i in {2..${max}}; do echo $i; done works in zsh and ksh.

Well, as I didn't have the seq command installed on my system (Mac OS X v10.6.1 (Snow Leopard)), I ended up using a while loop instead:

max=5 i=1 while [ $max -gt $i ] do (stuff) done 

*Shrugs* Whatever works.

1

Here it worked on Mac OS X.

It includes the example of a BSD date, how to increment and decrement the date also:

for ((i=28; i>=6 ; i--)); do dat=`date -v-${i}d -j "+%Y%m%d"` echo $dat done 

These all do {1..8} and should all be POSIX. They also will not break if you put a conditional continue in the loop. The canonical way:

f= while [ $((f+=1)) -le 8 ] do echo $f done 

Another way:

g= while g=${g}1 [ ${#g} -le 8 ] do echo ${#g} done 

and another:

set -- while set $* . [ ${#} -le 8 ] do echo ${#} done 

Use:

max=10 for i in `eval echo {2..$max}` do echo $i done 

You need the explicit 'eval' call to reevaluate the {} after variable substitution.