bash-hackers-wiki/syntax/ccmd/c_for/index.html

117 lines
56 KiB
HTML
Raw Permalink Normal View History

<!doctype html><html lang=en class=no-js> <head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link href=https://flokoe.github.io/bash-hackers-wiki/syntax/ccmd/c_for/ rel=canonical><link href=../arithmetic_eval/ rel=prev><link href=../case/ rel=next><link rel=icon href=../../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.5.44"><title>The C-style for-loop - The Bash Hackers Wiki</title><link rel=stylesheet href=../../../assets/stylesheets/main.0253249f.min.css><link rel=stylesheet href=../../../assets/stylesheets/palette.06af60db.min.css><link rel=preconnect href=https://fonts.gstatic.com crossorigin><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback"><style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style><script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script></head> <body dir=ltr data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer autocomplete=off> <input class=md-toggle data-md-toggle=search type=checkbox id=__search autocomplete=off> <label class=md-overlay for=__drawer></label> <div data-md-component=skip> <a href=#the-c-style-for-loop class=md-skip> Skip to content </a> </div> <div data-md-component=announce> </div> <header class=md-header data-md-component=header> <nav class="md-header__inner md-grid" aria-label=Header> <a href=../../.. title="The Bash Hackers Wiki" class="md-header__button md-logo" aria-label="The Bash Hackers Wiki" data-md-component=logo> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg> </a> <label class="md-header__button md-icon" for=__drawer> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg> </label> <div class=md-header__title data-md-component=header-title> <div class=md-header__ellipsis> <div class=md-header__topic> <span class=md-ellipsis> The Bash Hackers Wiki </span> </div> <div class=md-header__topic data-md-component=header-topic> <span class=md-ellipsis> The C-style for-loop </span> </div> </div> </div> <form class=md-header__option data-md-component=palette> <input class=md-option data-md-color-media data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to dark mode" type=radio name=__palette id=__palette_0> <label class="md-header__button md-icon" title="Switch to dark mode" for=__palette_1 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> <input class=md-option data-md-color-media data-md-color-scheme=slate data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to light mode" type=radio name=__palette id=__palette_1> <label class="md-header__button md-icon" title="Switch to light mode" for=__palette_0 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> </form> <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchM
&lt;LIST&gt;
done
# as a special case: without semicolon after ((...))
for (( &lt;EXPR1&gt; ; &lt;EXPR2&gt; ; &lt;EXPR3&gt; )) do
&lt;LIST&gt;
done
# alternative, historical and undocumented syntax
for (( &lt;EXPR1&gt; ; &lt;EXPR2&gt; ; &lt;EXPR3&gt; )) {
&lt;LIST&gt;
}
</code></pre></div> <h2 id=description>Description<a class=headerlink href=#description title="Permanent link">&para;</a></h2> <p>The C-style for-loop is a <a href=../../basicgrammar/#compound_commands>compound command</a> derived from the equivalent ksh88 feature, which is in turn derived from the C "for" keyword. Its purpose is to provide a convenient way to evaluate arithmetic expressions in a loop, plus initialize any required arithmetic variables. It is one of the main "loop with a counter" mechanisms available in the language.</p> <p>The <code>((;;))</code> syntax at the top of the loop is not an ordinary <a href=../arithmetic_eval/ >arithmetic compound command</a>, but is part of the C-style for-loop's own syntax. The three sections separated by semicolons are <a href=../../arith_expr/ >arithmetic expression</a> contexts. Each time one of the sections is to be evaluated, the section is first processed for: brace, parameter, command, arithmetic, and process substitution/expansion as usual for arithmetic contexts. When the loop is entered for the first time, <code>&lt;EXPR1&gt;</code> is evaluated, then <code>&lt;EXPR2&gt;</code> is evaluated and checked. If <code>&lt;EXPR2&gt;</code> is true, then the loop body is executed. After the first and all subsequent iterations, <code>&lt;EXPR1&gt;</code> is skipped, <code>&lt;EXPR3&gt;</code> is evaluated, then <code>&lt;EXPR2&gt;</code> is evaluated and checked again. This process continues until <code>&lt;EXPR2&gt;</code> is false.</p> <ul> <li><code>&lt;EXPR1&gt;</code> is to <strong>initialize variables</strong> before the first run.</li> <li><code>&lt;EXPR2&gt;</code> is to <strong>check</strong> for a termination condition. This is always the last section to evaluate prior to leaving the loop.</li> <li><code>&lt;EXPR3&gt;</code> is to <strong>change</strong> conditions after every iteration. For example, incrementing a counter.</li> </ul> <p>:!: If one of these arithmetic expressions in the for-loop is empty, it behaves as if it would be 1 (<strong>TRUE</strong> in arithmetic context).</p> <p>:!: Like all loops (Both types of <code>for</code>-loop, <code>while</code> and <code>until</code>), this loop can be:</p> <ul> <li>Terminated (broken) by the <code>break</code> builtin, optionally as <code>break N</code> to break out of <code>N</code> levels of nested loops.</li> <li>Forced immediately to the next iteration using the <code>continue</code> builtin, optionally as the <code>continue N</code> analog to <code>break N</code>.</li> </ul> <p>The equivalent construct using a <a href=../while_loop/ >while loop</a> and the <a href=../arithmetic_eval/ >arithmetic expression compound command</a> would be structured as:</p> <div class=highlight><pre><span></span><code>(( &lt;EXPR1&gt; ))
while (( &lt;EXPR2&gt; )); do
&lt;LIST&gt;
(( &lt;EXPR3&gt; ))
done
</code></pre></div> <p>The equivalent <code>while</code> construct isn't exactly the same, because both, the <code>for</code> and the <code>while</code> loop behave differently in case you use the <code>continue</code> command.</p> <h3 id=alternate-syntax>Alternate syntax<a class=headerlink href=#alternate-syntax title="Permanent link">&para;</a></h3> <p>Bash, Ksh93, Mksh, and Zsh also provide an alternate syntax for the <code>for</code> loop - enclosing the loop body in <code>{...}</code> instead of <code>do ... done</code>:</p> <div class=highlight><pre><span></span><code>for ((x=1; x&lt;=3; x++))
{
echo $x
}
</code></pre></div> <p>This syntax is <strong>not documented</strong> and shouldn't 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 compatibility reasons. Unlike the other aforementioned shells, Bash does not support the analogous syntax for <a href=../case/#portability_considerations>case..esac</a>.</p> <h3 id=return-status>Return status<a class=headerlink href=#return-status title="Permanent link">&para;</a></h3> <p>The return status is that of the last command executed from <code>&lt;LIST&gt;</code>, or <code>FALSE</code> if any of the arithmetic expressions failed.</p> <h2 id=alternatives-and-best-practice>Alternatives and best practice<a class=headerlink href=#alternatives-and-best-practice title="Permanent link">&para;</a></h2> <div center round todo 60%>TODO: Show some alternate usages involving functions and local variables for initialization.</div> <h2 id=examples>Examples<a class=headerlink href=#examples title="Permanent link">&para;</a></h2> <h3 id=simple-counter>Simple counter<a class=headerlink href=#simple-counter title="Permanent link">&para;</a></h3> <p>A simple counter, the loop iterates 101 times ("0" to "100" are 101 numbers -&gt; 101 runs!), and everytime the variable <code>x</code> is set to the current value.</p> <ul> <li>It <strong>initializes</strong> <code>x = 0</code></li> <li>Before every iteration it <strong>checks</strong> if <code>x ≤ 100</code></li> <li> <p>After every iteration it <strong>changes</strong> <code>x++</code></p> <p>for ((x = 0 ; x &lt;= 100 ; x++)); do echo "Counter: $x" done</p> </li> </ul> <h3 id=stepping-counter>Stepping counter<a class=headerlink href=#stepping-counter title="Permanent link">&para;</a></h3> <p>This is the very same counter (compare it to the simple counter example above), but the <strong>change</strong> that is made is a <code>x += 10</code>. That means, it will count from 0 to 100, but with a <strong>step of 10</strong>.</p> <div class=highlight><pre><span></span><code>for ((x = 0 ; x &lt;= 100 ; x += 10)); do
echo &quot;Counter: $x&quot;
done
</code></pre></div> <h3 id=bits-analyzer>Bits analyzer<a class=headerlink href=#bits-analyzer title="Permanent link">&para;</a></h3> <p>This example loops through the bit-values of a Byte, beginning from 128, ending at 1. If that bit is set in the <code>testbyte</code>, it prints "<code>1</code>", else "<code>0</code>" =&gt; it prints the binary representation of the <code>testbyte</code> value (8 bits).</p> <div class=highlight><pre><span></span><code>#!/usr/bin/env bash
# Example written for http://wiki.bash-hackers.org/syntax/ccmd/c_for#bits_analyzer
# Based on TheBonsai&#39;s original.
function toBin {
typeset m=$1 n=2 x=&#39;x[(n*=2)&gt;m]&#39;
for ((x = x; n /= 2;)); do
printf %d $(( m &amp; n &amp;&amp; 1))
done
}
function main {
[[ $1 == +([0-9]) ]] || return
typeset result
if (( $(ksh -c &#39;printf %..2d $1&#39; _ &quot;$1&quot;) == ( result = $(toBin &quot;$1&quot;) ) )); then
printf &#39;%s is %s in base 2!\n&#39; &quot;$1&quot; &quot;$result&quot;
else
echo &#39;Oops, something went wrong with our calculation.&#39; &gt;&amp;2
exit 1
fi
}
main &quot;${1:-123}&quot;
# vim: set fenc=utf-8 ff=unix ft=sh :
&lt;div hide&gt;
testbyte=123
for (( n = 128 ; n &gt;= 1 ; n /= 2 )); do
if (( testbyte &amp; n )); then
printf %d 1
else
printf %s 0
fi
done
echo
&lt;/div&gt;
</code></pre></div> <p>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...</p> <p>We arrive at 128 for <code>n</code> through the recursive arithmetic expression stored in <code>x</code>, which calculates the next-greatest power of 2 after <code>m</code>. To show that it works, we use ksh93 to double-check the answer, because it has a built-in feature for <code>printf</code> 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.</p> <h3 id=up-down-up-down>Up, down, up, down...<a class=headerlink href=#up-down-up-down title="Permanent link">&para;</a></h3> <p>This counts up and down from <code>0</code> to <code>${1:-5}</code>, <code>${2:-4}</code> times, demonstrating more complicated arithmetic expressions with multiple variables.</p> <div class=highlight><pre><span></span><code>for (( incr = 1, n=0, times = ${2:-4}, step = ${1:-5}; (n += incr) % step || (incr *= -1, --times);)); do
printf &#39;%*s\n&#39; &quot;$((n+1))&quot; &quot;$n&quot;
done
</code></pre></div> <div class=highlight><pre><span></span><code><a id=__codelineno-0-1 name=__codelineno-0-1 href=#__codelineno-0-1></a>~<span class=w> </span><span class=se>\$</span><span class=w> </span>bash<span class=w> </span>&lt;<span class=o>(</span>xclip<span class=w> </span>-o<span class=o>)</span><span class=w> </span><span class=m>1</span>
<a id=__codelineno-0-2 name=__codelineno-0-2 href=#__codelineno-0-2></a>
<a id=__codelineno-0-3 name=__codelineno-0-3 href=#__codelineno-0-3></a><span class=w> </span><span class=m>2</span>
<a id=__codelineno-0-4 name=__codelineno-0-4 href=#__codelineno-0-4></a><span class=w> </span><span class=m>3</span>
<a id=__codelineno-0-5 name=__codelineno-0-5 href=#__codelineno-0-5></a><span class=w> </span><span class=m>4</span>
<a id=__codelineno-0-6 name=__codelineno-0-6 href=#__codelineno-0-6></a><span class=w> </span><span class=m>5</span>
<a id=__codelineno-0-7 name=__codelineno-0-7 href=#__codelineno-0-7></a><span class=w> </span><span class=m>4</span>
<a id=__codelineno-0-8 name=__codelineno-0-8 href=#__codelineno-0-8></a><span class=w> </span><span class=m>3</span>
<a id=__codelineno-0-9 name=__codelineno-0-9 href=#__codelineno-0-9></a><span class=w> </span><span class=m>2</span>
<a id=__codelineno-0-10 name=__codelineno-0-10 href=#__codelineno-0-10></a>
<a id=__codelineno-0-11 name=__codelineno-0-11 href=#__codelineno-0-11></a><span class=m>1</span><span class=w> </span><span class=m>0</span><span class=w> </span><span class=m>1</span>
<a id=__codelineno-0-12 name=__codelineno-0-12 href=#__codelineno-0-12></a>
<a id=__codelineno-0-13 name=__codelineno-0-13 href=#__codelineno-0-13></a><span class=w> </span><span class=m>2</span>
<a id=__codelineno-0-14 name=__codelineno-0-14 href=#__codelineno-0-14></a><span class=w> </span><span class=m>3</span>
<a id=__codelineno-0-15 name=__codelineno-0-15 href=#__codelineno-0-15></a><span class=w> </span><span class=m>4</span>
<a id=__codelineno-0-16 name=__codelineno-0-16 href=#__codelineno-0-16></a><span class=w> </span><span class=m>5</span>
<a id=__codelineno-0-17 name=__codelineno-0-17 href=#__codelineno-0-17></a><span class=w> </span><span class=m>4</span>
<a id=__codelineno-0-18 name=__codelineno-0-18 href=#__codelineno-0-18></a><span class=w> </span><span class=m>3</span>
<a id=__codelineno-0-19 name=__codelineno-0-19 href=#__codelineno-0-19></a><span class=w> </span><span class=m>2</span>
<a id=__codelineno-0-20 name=__codelineno-0-20 href=#__codelineno-0-20></a>
<a id=__codelineno-0-21 name=__codelineno-0-21 href=#__codelineno-0-21></a><span class=m>1</span>
</code></pre></div> <h2 id=portability-considerations>Portability considerations<a class=headerlink href=#portability-considerations title="Permanent link">&para;</a></h2> <ul> <li>C-style for loops aren't POSIX. They are available in Bash, ksh93, and zsh. All 3 have essentially the same syntax and behavior.</li> <li>C-style for loops aren't available in mksh.</li> </ul> <h2 id=bugs>Bugs<a class=headerlink href=#bugs title="Permanent link">&para;</a></h2> <ul> <li><em>Fixed in 4.3</em>. ~~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.~~</li> </ul> <h2 id=see-also>See also<a class=headerlink href=#see-also title="Permanent link">&para;</a></h2> <ul> <li>Internal: <a href=../../arith_expr/ >Arithmetic expressions</a></li> <li>Internal: <a href=../classic_for/ >The classic for-loop</a></li> <li>Internal: <a href=../while_loop/ >The while-loop</a></li> </ul> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date">November 13, 2024</span> </span> <span class=md-source-file__fact> <span class=md-icon title=Created> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M14.47 15.08 11 13V7h1.5v5.25l3.08 1.83c-.41.28-.79.62-1.11 1m-1.39 4.84c-.36.05-.71.08-1.08.08-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8c0 .37-.03.72-.08 1.08.69.1 1.33.32 1.92.64.1-.56.16-1.13.16-1.72 0-5.5-4.5-10-10-10S2 6.5 2 12s4.47 10 10 10c.59 0 1.16-.06 1.72-.16-.32-.59-.54-1.23-.64-1.92M18 15v3h-3v2h3v3h2v-3h3v-2h-3v-3z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date">November 13, 2024</span> </span> </aside> <h2 id=__comments>Comments</h2> <script src=https://giscus.app/client.js data-repo=flokoe/bash-hackers-wiki data-repo-id=R_kgDOJ3Nr6Q data-category="Giscus Page Comments" data-category-id=DIC_kwDOJ3Nr6c4CXq9t data-mapping=pathname data-strict=1 data-reactions-enabled=1 data-emit-metadata=0 data-input-position=top data-theme=preferred_color_scheme data-lang=en data-loading=lazy crossorigin=anonymous async>
</script> <script>
var giscus = document.querySelector("script[src*=giscus]")
/* Set palette on initial load */
var palette = __md_get("__palette")
if (palette && typeof palette.color === "object") {
var theme = palette.color.scheme === "slate" ? "dark" : "light"
giscus.setAttribute("data-theme", theme)
}
/* Register event handlers after documented loaded */
document.addEventListener("DOMContentLoaded", function() {
var ref = document.querySelector("[data-md-component=palette]")
ref.addEventListener("change", function() {
var palette = __md_get("__palette")
if (palette && typeof palette.color === "object") {
var theme = palette.color.scheme === "slate" ? "dark" : "light"
/* Instruct Giscus to change theme */
var frame = document.querySelector(".giscus-frame")
frame.contentWindow.postMessage(
{ giscus: { setConfig: { theme } } },
"https://giscus.app"
)
}
})
})
</script> </article> </div> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> <button type=button class="md-top md-icon" data-md-component=top hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg> Back to top </button> </main> <footer class=md-footer> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-copyright> Made with <a href=https://squidfunk.github.io/mkdocs-material/ target=_blank rel=noopener> Material for MkDocs </a> </div> </div> </div> </footer> </div> <div class=md-dialog data-md-component=dialog> <div class="md-dialog__inner md-typeset"></div> </div> <script id=__config type=application/json>{"base": "../../..", "features": ["navigation.instant", "navigation.tracking", "navigation.tabs", "navigation.sections", "navigation.top", "content.action.view", "content.action.edit", "search.suggest", "search.highlight", "content.code.copy"], "search": "../../../assets/javascripts/workers/search.6ce7567c.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script> <script src=../../../assets/javascripts/bundle.83f73b43.min.js></script> </body> </html>