This is an old revision of the document!


The C-style for-loop

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

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

# alternative, historical and undocumented syntax

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

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 1)

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
  <LIST>
  (( <EXPR3> ))
done

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

Return status

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

Simple counter

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"
done

Stepping counter

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"
done

Bits analyzer

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

testbyte=123
for (( n = 128 ; n >= 1 ; n = n / 2 )); do
  if (( testbyte & n )); then
    echo -n "1"
  else
    echo -n "0"
  fi
done
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…

Up, down, up, down...

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
12345678987654321012345678987654321012345678987654321012345678987654321012345678987654321012345678

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.

* There appears to be a bug as of Bash 4.2p10 in which command lists cannot be distinguished from the for loop's arithmetic argument delimiter (both semicolons), so command substitutions within the C-style for loop expression cannot contain more than one command. This appears specific to Bash. ksh93 and zsh behave correctly. It's also pretty obscure and useless - you probably shouldn't be doing that anyway.

EDIT: Chet says it'll be fixed in the next version. :-)


1)
However, as with all arithmetic, it is possible to have command substitutions contained within. Note that command substitutions are processed before arithmetic, so any control flow such as the ternary operator, or short circuiting, have no effect on the command substitution's evaluation. Rather, the expression resulting from the command substitution's output plus surrounding text ends up processed as arithmetic. See also the above bug.
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.1320212133.txt
  • Last modified: 2011/11/02 05:35
  • by ormaaj