264

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
  • 2
    what system and shell are you using? What kind of goofy system has sh or bash, but doesn't have seq, a coreutil? Commented Sep 18, 2009 at 16:08
  • 13
    FreeBSD doesn't. Commented Sep 18, 2009 at 16:12
  • Small style nit: I usually see the do and then keywords on the same line as for and if, respectively. E.g., for i in {2..10}; do Commented Sep 18, 2009 at 16:33
  • possible duplicate of Is it possible to use a variable in for syntax in bash?
    – Barmar
    Commented Aug 1, 2013 at 15:00
  • FreeBSD, at least 10, does have /usr/bin/seq.
    – jrm
    Commented May 10, 2015 at 18:46

11 Answers 11

317

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
  • There is no good reason to use an external command such as seq to count and increment numbers in the for loop, hence it is recommend that you avoid using seq. This command is left for compatibility with old bash. The built-in commands are fast enough. for (( EXP1; EXP2; EXP3 )) ...
    – miller
    Commented Jul 25, 2016 at 9:27
  • 17
    @miller the for (( ... )) syntax isn't POSIX and that means for example that it won't work out of the box on things like Alpine Linux. seq does.
    – Wernight
    Commented Sep 30, 2016 at 22:21
  • @Wernight Not just Alpine Linux; #!/bin/sh is Dash in Debian/Ubuntu. Commented Mar 12, 2019 at 20:50
101

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
  • 1
    @Flow: Hm, I just tried it on a couple of systems (Linux and BSD based) with #!/bin/sh and it worked fine. Invoked under bash and specifically under /bin/sh, still worked. Maybe the version of sh matters? Are you on some old Unix? Commented Mar 26, 2012 at 21:29
  • 8
    Very few systems have a dedicated sh, instead making it a link to other another shell. Ideally, such a shell invoked as sh would only support those features in the POSIX standard, but by default let some of their extra features through. The C-style for-loop is not a POSIX feature, but may be in sh mode by the actual shell.
    – chepner
    Commented Sep 12, 2013 at 19:41
39

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 < 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
3
  • 4
    true $(( i++ )) doesn't work in all cases, so most portable would be true $((i=i+1)).
    – Flow
    Commented Mar 22, 2012 at 14:50
  • semi colon should not come in "for (( i=0; i < max; i++ ));"
    – logan
    Commented Feb 10, 2014 at 13:02
  • jot 0 10 might be an infinite loop starting at 10. To get the same effect as max=10; for (( i=0; i < max; i++ )); do echo "output: $i"; done I think the syntax should be jot -w 'output: %d' 10 0 (directly print out sans loop) or just for i in $( jot 10 0 ); do ….. for the looped variant Commented May 26 at 1:20
19

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
19

We can iterate loop like as C programming.

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

There's more than one way to do it.

max=10
for i in `eval "echo {2..$max}"`
do
    echo "$i"
done
2
  • 7
    A security risk, since eval will evaluate anything you set max to. Consider max="2}; echo ha; #", then replace echo ha with something more destructive.
    – chepner
    Commented Sep 12, 2013 at 19:45
  • 7
    (S)he set max to 10. No risk. Commented Apr 21, 2014 at 1:13
5

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.

3

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
  • 2
    seq is relatively new. I only found out about it a few months ago. But you can use a 'for' loop!! The disadvantage of a 'while' is that you have to remember to increment the counter somewhere inside the loop, or else loop downwards. Commented Sep 18, 2009 at 16:23
2

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
1
  • Wonderful, I'm looking for a solution for busybox's ash, and your answer is perfect
    – kkocdko
    Commented Jan 27, 2023 at 19:57
2

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
1

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.