This is an old revision of the document!

The C-style for-loop

for (( <EXPR1> ; <EXPR2> ; <EXPR3> )); do

# as a special case: without semicolon after ((...))
for (( <EXPR1> ; <EXPR2> ; <EXPR3> )) do

# alternative, historical and undocumented syntax

for (( <EXPR1> ; <EXPR2> ; <EXPR3> )) {

The C-style for-loop is, as the name says, derived from the C-keyword "for", but in Bash, it only allows arithmetic expressions as header contents, not arbitrary commands.

It operates as follows: The arithmetic expression <EXPR1> is evaluated, then <EXPR2> is checked, if it's true, then the loop body is executed. After the first iteration, the <EXPR3> is evaluated, <EXPR2> is checked again, if it's true, the loop body is executed, etc…

  • <EXPR1> is to initialize before the first run
  • <EXPR2> is to check if the loop should be ran
  • <EXPR3> is to change conditions after every loop run

It's very simple. Another equivalent loop using a while-construct with arithmetic expressions compound command would be:

(( <EXPR1> ))
while (( <EXPR2> )); do
  (( <EXPR3> ))

If one of these arithmetic expressions in the for-loop is empty, it behaves as if it would be 1 (TRUE in arithmetic context).

:!: Like all loops (both for-loops, while and until), this loop can be

  • terminated (broken) by the break command, optionally as break N to break N levels of nested loops
  • forced to immediately do the next iteration using the continue command, optionally as continue N analog to break N

Bash knows an alternative syntax for the for loop, enclosing the loop body in {...} instead of do ... done:

for ((x=1; x<=3; x++))
  echo $x
This syntax is not documented and should not be used. I found the parser definitions for it in 1.x code, and in modern 4.x code. My guess is that it's there for compatiblity reasons. This syntax is not specified by POSIX(R).

The return status is the one of the last command executed from <LIST> or FALSE if any of the arithmetic expressions fail.

A simple counter, the loop iterates 101 times ("0" to "100" are 101 numbers → 101 runs!), and everytime the variable x is set to the current value.

  • it initializes x = 0
  • before every iteration it checks if x ⇐ 100
  • after every iteration it changes x++

for ((x = 0 ; x <= 100 ; x++)); do
  echo "Counter: $x"

This is the very same counter (compare it to the simple counter example above), but the change that is made is a x = x + 10. That means, it will count from 0 to 100, but with a step of 10.

for ((x = 0 ; x <= 100 ; x = x + 10)); do
  echo "Counter: $x"

This is a bit more complex, but really just a little bit.

It loops through the bit-values of a Byte, beginning from 128, ending at 1. If that bit is set in the testbyte, it prints "1", else "0" ⇒ it prints the binary representation of the testbyte value (8 bits).

for (( n = 128 ; n >= 1 ; n = n / 2 )); do
  if (( testbyte & n )); then
    echo -n "1"
    echo -n "0"
echo # final linefeed
Why that one begins at 128 (highest value, on the left) and not 1 (lowest value, on the right)? It's easier to print from left to right…

And finally, a really complicated example. This one counts up and down from 0 to 9, 10 times. Remember, each part of the C-style for loop can contain arbitrary arithmetic. Several arithmetic expression concepts are illustrated here such as C-style multiple-assignment (also used in languages like Python), use of multiple variables, the comma operator for delimiting side-effectful expressions, boolean short-circuiting, parens for grouping, and a few of the increment operators. Here, i is used to keep track of the count, j is the increment, which can be either 1 or -1, and k is the number of 0-9 counts completed.

$ for (( i = j = k = 1; i % 9 || (j *= -1, k++ <= 10); i += j )); do printf "$i"; done

The result, and therefore also truth value of a comma-delimited arithmetic expression list is that of the last expression of the list. In the middle expression of this for loop, if i % 9 is nonzero, it's the last expression performed and thus the entire expression is true. If it's zero, the short-circuit isn't tripped, and thus the truth of the expression is determined by the last expression of the following list: k++ <= 10. The parentheses are required because commas have the lowest precedence.

C-style for loops aren't POSIX. They are available in Bash, ksh93, and zsh. All 3 have essentially the same syntax and behavior.

This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information
Martin Kealey, 2013/06/06 02:43

It should be noted that the equivalence with the while-loop is approximate; it differ, in that "continue" in a for-loop will cause the 3rd ("increment") expression to be evaluated.

You could leave a comment if you were logged in.
  • syntax/ccmd/c_for.1319854908.txt
  • Last modified: 2011/10/29 02:21
  • by ormaaj