bash-hackers-wiki/commands/builtin/let/index.html

43 lines
48 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/commands/builtin/let/ rel=canonical><link href=../kill/ rel=prev><link href=../local/ 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 let builtin command - 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-let-builtin-command 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 let builtin command </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=matc
</code></pre></div> <h2 id=description>Description<a class=headerlink href=#description title="Permanent link">&para;</a></h2> <p>The <code>let</code> builtin command evaluates each supplied word from left to right as an <a href=../../../syntax/arith_expr/ >arithmetic expression</a> and returns an exit code according to the truth value of the rightmost expression.</p> <ul> <li>0 (TRUE) when <code>arg</code> evaluated to not 0 (arithmetic "true")</li> <li>1 (FALSE) when <code>arg</code> evaluated to 0 (arithmetic "false")</li> </ul> <p>For this return code mapping, please see <a href=../../../syntax/arith_expr/#arithmetic_expressions_and_return_codes>this section</a>. They work in the same way as <code>((</code>.</p> <h2 id=examples>Examples<a class=headerlink href=#examples title="Permanent link">&para;</a></h2> <p><code>let</code> is very similar to <a href=../../../syntax/ccmd/arithmetic_eval/ >((</a> - the only difference being <code>let</code> is a builtin (simple command), and <code>((</code> is a compound command. The arguments to <code>let</code> are therefore subject to all the same expansions and substitutions as any other simple command - requiring proper quoting and escaping - whereas the contents of <code>((</code> aren't subject to <a href=../../../syntax/expansion/wordsplit/ >word-splitting</a> or <a href=../../../syntax/expansion/globs/ >pathname expansion</a> (almost never desirable for arithmetic). For this reason, <strong>the <a href=../../../syntax/ccmd/arithmetic_eval/ >arithmetic compound command</a> should generally be preferred over <code>let</code></strong>.</p> <div class=highlight><pre><span></span><code>$ let &#39;b = a&#39; &quot;(a += 3) + $((a = 1)), b++&quot;
$ echo &quot;$a - $b - $?&quot;
4 - 2 - 0
</code></pre></div> <p>Is equivalent to the <a href=../../../syntax/ccmd/arithmetic_eval/ >arithmetic evaluation compound command</a>:</p> <div class=highlight><pre><span></span><code>$ (( b = a, (a += 3) + $((a = 1)), b++ ))
$ echo &quot;$a - $b - $?&quot;
4 - 2 - 0
</code></pre></div> <div class="admonition info"> <p>Remember that inside arithmetic evaluation contexts, all other expansions are processed as usual (from left-to-right), and the resulting text is evaluated as an arithmetic expression. Arithmetic already has a way to control precedence using parentheses, so it's very rare to need to nest arithmetic expansions within one another. It's used above only to illustrate how this precedence works.</p> </div> <p>Unlike <code>((</code>, being a simple command <code>let</code> has its own environment. In Bash, built-ins that can set variables process any arithmetic under their own environment, which makes the variable effectively "local" to the builtin unless the variable is also set or modified by the builtin. This differs in other shells, such as ksh93, where environment assignments to regular builtins are always local even if the variable is modified by the builtin.</p> <div class=highlight><pre><span></span><code> ~ $ ( y=1+1 let x=y; declare -p x y )
declare -- x=&quot;2&quot;
bash: declare: y: not found
~ $ ( y=1+1 let x=y++; declare -p x y )
declare -- x=&quot;2&quot;
declare -- y=&quot;3&quot;
</code></pre></div> <p>This can be useful in certain situations where a temporary variable is needed.</p> <h2 id=portability-considerations>Portability considerations<a class=headerlink href=#portability-considerations title="Permanent link">&para;</a></h2> <ul> <li>the <code>let</code> command is not specified by POSIX&reg;. The portable alternative is: <code>[ "$(( &lt;EXPRESSION&gt; ))" -ne 0 ]</code>. To make portable scripts simpler and cleaner, <code>let</code> can be defined as: <code># POSIX let() { IFS=, command eval test '$(($*))' -ne 0 }</code> Aside from differences in supported arithmetic features, this should be identical to the Bash/Ksh <code>let</code>.</li> <li>It seems to be a common misunderstanding that <code>let</code> has some legacy purpose. Both <code>let</code> and <a href=../../../syntax/ccmd/arithmetic_eval/ ><sup id=fnref:1><a class=footnote-ref href=#fn:1>1</a></sup></a> were ksh88 features and almost identical in terms of portability as everything that inherited one also tended to get the other. Don't choose <code>let</code> over <code>((</code> expecting it to work in more places.</li> <li><a href=http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expr.html#tag_20_42>expr(1)</a> is a command one is likely to come across sooner or later. While it is more "standard" than <code>let</code>, the above should always be preferred. Both <a href=../../../syntax/arith_expr/ >arithmetic expansion</a>s and the <code>[</code> test operator are specified by POSIX&reg; and satisfy almost all of expr's use-cases. Unlike <code>let</code>, <code>expr</code> cannot assign directly to bash variables but instead returns a result on stdout. <code>expr</code> takes each operator it recognizes as a separate word and then concatenates them into a single expression that's evaluated according to it's own rules (which differ from shell arithmetic). <code>let</code> parses each word it recieves on its own and evaluates it as an expression without generating any output other than a return code.</li> <li>For unknown reasons, <code>let</code> is one of the Bash commands with special parsing for arguments formatted like compound array assignments. See: <a href=../eval/#portability_considerations>eval</a> for details. There are no known practical uses for this. Parentheses are treated as grouping operators and compound assignment is not possible by arithmetic expressions.</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=../../../syntax/expansion/arith/ >arithmetic expansion</a></li> <li>Internal: <a href=../../../syntax/arith_expr/ >arithmetic expressions</a></li> <li>Internal: <a href=../../../syntax/ccmd/arithmetic_eval/ >arithmetic evaluation compound command</a></li> </ul> <div class=footnote> <hr> <ol> <li id=fn:1> <p>...&#160;<a class=footnote-backref href=#fnref:1 title="Jump back to footnote 1 in the text">&#8617;</a></p> </li> </ol> </div> <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> <sp
</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>