# Differences

This shows you the differences between two versions of the page.

​TODO:​ Show some alternate usages involving functions and local variables for initialization.​ ===== Examples ===== ===== Examples ===== + ==== Simple counter ==== ==== 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. 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''​ + * It **initializes** ''​x = 0''​ - * before ​every iteration it **checks** if ''​x ​<= 100''​ + * Before ​every iteration it **checks** if ''​x ​≤ 100''​ - * after every iteration it **changes** ''​x++''​ + * After every iteration it **changes** ''​x++''​ <​code>​ <​code>​ Line 78: Line 85: ==== Stepping counter ==== ==== 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**. + + This is the very same counter (compare it to the simple counter example above), but the **change** that is made is a ''​x ​+= 10''​. That means, it will count from 0 to 100, but with a **step of 10**. <​code>​ <​code>​ - for ((x = 0 ; x <= 100 ; x = x + 10)); do + for ((x = 0 ; x <= 100 ; x += 10)); do echo "​Counter:​ \$x" echo "​Counter:​ \$x" done done Line 87: Line 95: ==== Bits analyzer ==== ==== Bits analyzer ==== - This is a bit more complex, but really just a little ​bit. + This example 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). + <​code>​ + #​!/​usr/​bin/​env bash + # Example written for http://​wiki.bash-hackers.org/​syntax/​ccmd/​c_for#​bits_analyzer + # Based on TheBonsai'​s original. + + function toBin { + typeset m=\$1 n=2 x='​x[(n*=2)>​m]'​ + for ((x = x; n /= 2;)); do + printf %d \$(( m & n && 1)) + done + } + + function main { + [[ \$1 == +([0-9]) ]] || return + typeset result + if (( \$(ksh -c '​printf %..2d \$1' _ "​\$1"​) == ( result = \$(toBin "​\$1"​) ) )); then + printf '%s is %s in base 2!\n' "​\$1"​ "​\$result"​ + else + echo 'Oops, something went wrong with our calculation.' >&​2 + exit 1 + fi + } + + main "​\${1:​-123}"​ + + # vim: set fenc=utf-8 ff=unix ft=sh : + ​ - 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). +
<​code>​ <​code>​ testbyte=123 testbyte=123 - for (( n = 128 ; n >= 1 ; n = n / 2 )); do + for (( n = 128 ; n >= 1 ; n /= 2 )); do if (( testbyte & n )); then if (( testbyte & n )); then - ​echo -n "1" + ​printf %d 1 else else - ​echo -n "0" + ​printf %s 0 fi fi done done - echo # final linefeed + echo ​ + ​ + 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... 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... + + We arrive at 128 for ''​n''​ through the recursive arithmetic expression stored in ''​x'',​ which calculates the next-greatest power of 2 after ''​m''​. To show that it works, we use ksh93 to double-check the answer, because it has a built-in feature for ''​printf''​ to print a representation of any number in an arbitrary base (up to 64). Very few languages have that ability built-in, even things like Python. ==== Up, down, up, down... ==== ==== 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. + This counts up and down from ''​0''​ to ''​\${1:-5}''​, ''​\${2:-4}''​ times, demonstrating more complicated arithmetic expressions with multiple variables. - <​code>​\$ 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. + <​code>​ + for (( incr = 1, n=0, times = \${2:-4}, step = \${1:-5}; (n += incr) % step || (incr *= -1, --times);​));​ do + printf ​'%*s\n' ​"​\$((n+1))"​ "​\$n"​ + done + + ~ \$ bash <(xclip -o) + 1 + 2 + 3 + 4 + 5 + 4 + 3 + 2 + 1 + 0 + 1 + 2 + 3 + 4 + 5 + 4 + 3 + 2 + 1 + ===== Portability considerations ===== ===== Portability considerations ===== - C-style for loops aren't POSIX. They are available in Bash, ksh93, and zsh. All 3 have essentially the same syntax and behavior. + * C-style for loops aren't POSIX. They are available in Bash, ksh93, and zsh. All 3 have essentially the same syntax and behavior. + * C-style for loops aren't available in mksh. ===== Bugs ===== ===== Bugs ===== - 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. + * //Fixed in 4.3//. There appears to be a bug as of Bash 4.2p10 in which command lists can'​t ​be distinguished from the for loop's arithmetic argument delimiter (both semicolons),​ so command substitutions within the C-style for loop expression ​can'​t ​contain more than one command.​ ===== See also ===== ===== See also =====
• syntax/ccmd/c_for.1319872125.txt