232

The way to iterate over a range in bash is

for i in {0..10}; do echo $i; done 

What would be the syntax for iterating over the sequence with a step? Say, I would like to get only even number in the above example.

3
  • 1
    Even numbers, multiply i by 2. :P Commented Jun 8, 2009 at 17:38
  • 1
    multiplication is rather ugly, I should say Commented Jun 8, 2009 at 18:18
  • 2
    @Omnifarious I would not be so sure. OS X still comes with 3.2, for example. I would say the C-style loop should be accepted. Commented Oct 5, 2018 at 17:21

8 Answers 8

283

I'd do

for i in `seq 0 2 10`; do echo $i; done 

(though of course seq 0 2 10 will produce the same output on its own).

Note that seq allows floating-point numbers (e.g., seq .5 .25 3.5) but bash's brace expansion only allows integers.

Sign up to request clarification or add additional context in comments.

4 Comments

I'll hazard a guess that the downvote was due to your answer being generic to 'sh', and not specific to 'bash'. The pure Bash approach {begin end step} performs just a little better.The older 'seq' method's handy on older or smaller-memory systems like busybox. I did upvote both your and TheBonsai's answer. :)
Prefer $(...) to backquotes. Backquotes do not nest sanely.
seq 1000000 1000010 only does floats, actually - there's no way to make it do integers! Brace expansion works.
How could I save result(output) into a file?
169

Bash 4's brace expansion has a step feature:

for {0..10..2}; do .. done 

No matter if Bash 2/3 (C-style for loop, see answers above) or Bash 4, I would prefer anything over the 'seq' command.

7 Comments

and btw, do you know if bash4 is default on any major OS?
Bash4 still isn't mainstream, no. Why not seq? Well, let's say it with the words of the bot in the IRC channel #bash: "seq(1) is a highly nonstandard external command used to count to 10 in silly Linux howtos."
my understanding is that seq is a part of coreutils. what is non-standard about it? arguments? thanks for your help.
These arguments may or may not count for you: * there are enough systems without GNU coreutils (but Bash installed) * you create an unneeded external process * you rely on the idea that all 'seq' do what your 'seq' does * it's not standardized by the ISO
@becko If the step is stored in the variable i, then you can't do for {0..10..${i}} .. it fails.
|
109

Pure Bash, without an extra process:

for (( COUNTER=0; COUNTER<=10; COUNTER+=2 )); do echo $COUNTER done 

5 Comments

+1 Because the step can be replaced by a variable too.
I think this is really what most people likely want -- a simple way to do a loop with a prescribed step value. It sounds simpler than all of the seq based answers, and is a clearer syntax than Bash4 brace expansion, and looks like it would allow for variables (I haven't tried that, but the syntax definitely suggests that).
Works in Bash 3, unlike @TheBonsai's answer.
It even resolves variable, ((i="$first" ; i<="$last" ; i+="$step")). Not so easy with curly braces and seq.
This is sometimes much faster than {0..10..2}-style, e.g. when the range is really large.
27
#!/bin/bash for i in $(seq 1 2 10) do echo "skip by 2 value $i" done 

3 Comments

seq is a Linux command. This won't be available on Mac OS X or FreeBSD.
FWIW seq is available in my standard OS X Mavericks 10.9.1
I have try some other sintax, but that is the only is working for my on a little CentOS. @z - has saved my day :D
20

Use seq command:

$ seq 4 1 2 3 4 $ seq 2 5 2 3 4 5 $ seq 4 2 12 4 6 8 10 12 $ seq -w 4 2 12 04 06 08 10 12 $ seq -s, 4 1,2,3,4 

Comments

7

brace expansion {m..n..s} is more efficient than seq. AND it allows a bit of output formatting:

$ echo {0000..0010..2} 0000 0002 0004 0006 0008 0010 

which is useful if one numbers e.g. files and want's a sorted output of 'ls'.

2 Comments

Be aware that some programs may read 0010 as 8 (i.e. they read octal when there is a leading 0 because this is done in C).
This works to my surprise while running GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu) . Apparently and somehow inconsistently the leading zero isn't considered to be an octal number indicator as in echo $((020+001)) which prints 17, where echo {000..020..002} prints 000 002 004 006 008 010 012 014 016 018 020
0

Often, it is desirable to use that sequence as an array. I suggest the following function:

sh_range(){ local from="$1" local to="$2" local -n _sh_range_out="$3" local i _sh_range_out=() for((i=$from; i<=$to; i++)); do _sh_range_out+=("$i") done } sh_range 1 3 array declare -p array >>> declare -a array=([0]="1" [1]="2" [2]="3") 

Comments

0

I will be a little repetitive, but no other answer mentions that the built-in `seq` command can be used with a custom format to print the sequence. I discovered it as I was about to write a helper to give me that and was glad it was not needed after all :)

seq -f "Foo %g" 3 # Prints "Foo 1", "Foo 2", "Foo 3", each on separate line 

The options must come first, i.e. seq [OPTIONS...] [FIRST [INCREMENT]] LAST with the first number and increment being both optional. The numbers can also be floats, and then %.3f can be used in formatting, where 3 is the decimal precision.

Other useful options are -s "," to specify a custom separator (default to a new line), and -w to pad the numbers with leading zeros for a fixed width (cannot be used together with -f).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.