bash-hackers-wiki/howto/mutex/index.html

105 lines
64 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/howto/mutex/ rel=canonical><link href=../getopts_tutorial/ rel=prev><link href=../pax/ rel=next><link rel=icon href=../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.5.44"><title>Lock your script (against parallel execution) - 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=#lock-your-script-against-parallel-execution 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> Lock your script (against parallel execution) </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-co
* it will set an unsuccesful exit code if an error occours - for example, if the directory specified already exists
</code></pre></div> <p>With mkdir it seems, we have our two steps in one simple operation. A (very!) simple locking code might look like this:</p> <div class=highlight><pre><span></span><code><a id=__codelineno-0-1 name=__codelineno-0-1 href=#__codelineno-0-1></a><span class=k>if</span><span class=w> </span>mkdir<span class=w> </span>/var/lock/mylock<span class=p>;</span><span class=w> </span><span class=k>then</span>
<a id=__codelineno-0-2 name=__codelineno-0-2 href=#__codelineno-0-2></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;Locking succeeded&quot;</span><span class=w> </span>&gt;<span class=p>&amp;</span><span class=m>2</span>
<a id=__codelineno-0-3 name=__codelineno-0-3 href=#__codelineno-0-3></a><span class=k>else</span>
<a id=__codelineno-0-4 name=__codelineno-0-4 href=#__codelineno-0-4></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;Lock failed - exit&quot;</span><span class=w> </span>&gt;<span class=p>&amp;</span><span class=m>2</span>
<a id=__codelineno-0-5 name=__codelineno-0-5 href=#__codelineno-0-5></a><span class=w> </span><span class=nb>exit</span><span class=w> </span><span class=m>1</span>
<a id=__codelineno-0-6 name=__codelineno-0-6 href=#__codelineno-0-6></a><span class=k>fi</span>
</code></pre></div> <p>In case <code>mkdir</code> reports an error, the script will exit at this point - <strong>the MUTEX did its job!</strong></p> <p><em>If the directory is removed after setting a successful lock, while the script is still running, the lock is lost. Doing chmod -w for the parent directory containing the lock directory can be done, but it is not atomic. Maybe a while loop checking continously for the existence of the lock in the background and sending a signal such as USR1, if the directory is not found, can be done. The signal would need to be trapped. I am sure there there is a better solution than this suggestion</em> --- <strong>sn18</strong> 2009/12/19 08:24*</p> <p><strong>Note:</strong> While perusing the Internet, I found some people asking if the <code>mkdir</code> method works "on all filesystems". Well, let's say it should. The syscall under <code>mkdir</code> is guarenteed to work atomicly in all cases, at least on Unices. Two examples of problems are NFS filesystems and filesystems on cluster servers. With those two scenarios, dependencies exist related to the mount options and implementation. However, I successfully use this simple method on an Oracle OCFS2 filesystem in a 4-node cluster environment. So let's just say "it should work under normal conditions".</p> <p>Another atomic method is setting the <code>noclobber</code> shell option (<code>set -C</code>). That will cause redirection to fail, if the file the redirection points to already exists (using diverse <code>open()</code> methods). Need to write a code example here.</p> <div class=highlight><pre><span></span><code><a id=__codelineno-1-1 name=__codelineno-1-1 href=#__codelineno-1-1></a><span class=k>if</span><span class=w> </span><span class=o>(</span><span class=w> </span><span class=nb>set</span><span class=w> </span>-o<span class=w> </span>noclobber<span class=p>;</span><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;locked&quot;</span><span class=w> </span>&gt;<span class=w> </span><span class=s2>&quot;</span><span class=nv>$lockfile</span><span class=s2>&quot;</span><span class=o>)</span><span class=w> </span><span class=m>2</span>&gt;<span class=w> </span>/dev/null<span class=p>;</span><span class=w> </span><span class=k>then</span>
<a id=__codelineno-1-2 name=__codelineno-1-2 href=#__codelineno-1-2></a><span class=w> </span><span class=nb>trap</span><span class=w> </span><span class=s1>&#39;rm -f &quot;$lockfile&quot;; exit $?&#39;</span><span class=w> </span>INT<span class=w> </span>TERM<span class=w> </span>EXIT
<a id=__codelineno-1-3 name=__codelineno-1-3 href=#__codelineno-1-3></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;Locking succeeded&quot;</span><span class=w> </span>&gt;<span class=p>&amp;</span><span class=m>2</span>
<a id=__codelineno-1-4 name=__codelineno-1-4 href=#__codelineno-1-4></a><span class=w> </span>rm<span class=w> </span>-f<span class=w> </span><span class=s2>&quot;</span><span class=nv>$lockfile</span><span class=s2>&quot;</span>
<a id=__codelineno-1-5 name=__codelineno-1-5 href=#__codelineno-1-5></a><span class=k>else</span>
<a id=__codelineno-1-6 name=__codelineno-1-6 href=#__codelineno-1-6></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;Lock failed - exit&quot;</span><span class=w> </span>&gt;<span class=p>&amp;</span><span class=m>2</span>
<a id=__codelineno-1-7 name=__codelineno-1-7 href=#__codelineno-1-7></a><span class=w> </span><span class=nb>exit</span><span class=w> </span><span class=m>1</span>
<a id=__codelineno-1-8 name=__codelineno-1-8 href=#__codelineno-1-8></a><span class=k>fi</span>
</code></pre></div> <p>Another explanation of this basic pattern using <code>set -C</code> can be found <a href=http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html#tag_23_02_07>here</a>.</p> <h2 id=an-example>An example<a class=headerlink href=#an-example title="Permanent link">&para;</a></h2> <p>This code was taken from a production grade script that controls PISG to create statistical pages from my IRC logfiles. There are some differences compared to the very simple example above:</p> <ul> <li>the locking stores the process ID of the locked instance</li> <li>if a lock fails, the script tries to find out if the locked instance still is active (unreliable!)</li> <li>traps are created to automatically remove the lock when the script terminates, or is killed</li> </ul> <p>Details on how the script is killed aren't given, only code relevant to the locking process is shown:</p> <div class=highlight><pre><span></span><code><a id=__codelineno-2-1 name=__codelineno-2-1 href=#__codelineno-2-1></a><span class=ch>#!/bin/bash</span>
<a id=__codelineno-2-2 name=__codelineno-2-2 href=#__codelineno-2-2></a>
<a id=__codelineno-2-3 name=__codelineno-2-3 href=#__codelineno-2-3></a><span class=c1># lock dirs/files</span>
<a id=__codelineno-2-4 name=__codelineno-2-4 href=#__codelineno-2-4></a><span class=nv>LOCKDIR</span><span class=o>=</span><span class=s2>&quot;/tmp/statsgen-lock&quot;</span>
<a id=__codelineno-2-5 name=__codelineno-2-5 href=#__codelineno-2-5></a><span class=nv>PIDFILE</span><span class=o>=</span><span class=s2>&quot;</span><span class=si>${</span><span class=nv>LOCKDIR</span><span class=si>}</span><span class=s2>/PID&quot;</span>
<a id=__codelineno-2-6 name=__codelineno-2-6 href=#__codelineno-2-6></a>
<a id=__codelineno-2-7 name=__codelineno-2-7 href=#__codelineno-2-7></a><span class=c1># exit codes and text</span>
<a id=__codelineno-2-8 name=__codelineno-2-8 href=#__codelineno-2-8></a><span class=nv>ENO_SUCCESS</span><span class=o>=</span><span class=m>0</span><span class=p>;</span><span class=w> </span>ETXT<span class=o>[</span><span class=m>0</span><span class=o>]=</span><span class=s2>&quot;ENO_SUCCESS&quot;</span>
<a id=__codelineno-2-9 name=__codelineno-2-9 href=#__codelineno-2-9></a><span class=nv>ENO_GENERAL</span><span class=o>=</span><span class=m>1</span><span class=p>;</span><span class=w> </span>ETXT<span class=o>[</span><span class=m>1</span><span class=o>]=</span><span class=s2>&quot;ENO_GENERAL&quot;</span>
<a id=__codelineno-2-10 name=__codelineno-2-10 href=#__codelineno-2-10></a><span class=nv>ENO_LOCKFAIL</span><span class=o>=</span><span class=m>2</span><span class=p>;</span><span class=w> </span>ETXT<span class=o>[</span><span class=m>2</span><span class=o>]=</span><span class=s2>&quot;ENO_LOCKFAIL&quot;</span>
<a id=__codelineno-2-11 name=__codelineno-2-11 href=#__codelineno-2-11></a><span class=nv>ENO_RECVSIG</span><span class=o>=</span><span class=m>3</span><span class=p>;</span><span class=w> </span>ETXT<span class=o>[</span><span class=m>3</span><span class=o>]=</span><span class=s2>&quot;ENO_RECVSIG&quot;</span>
<a id=__codelineno-2-12 name=__codelineno-2-12 href=#__codelineno-2-12></a>
<a id=__codelineno-2-13 name=__codelineno-2-13 href=#__codelineno-2-13></a><span class=c1>###</span>
<a id=__codelineno-2-14 name=__codelineno-2-14 href=#__codelineno-2-14></a><span class=c1>### start locking attempt</span>
<a id=__codelineno-2-15 name=__codelineno-2-15 href=#__codelineno-2-15></a><span class=c1>###</span>
<a id=__codelineno-2-16 name=__codelineno-2-16 href=#__codelineno-2-16></a>
<a id=__codelineno-2-17 name=__codelineno-2-17 href=#__codelineno-2-17></a><span class=nb>trap</span><span class=w> </span><span class=s1>&#39;ECODE=$?; echo &quot;[statsgen] Exit: ${ETXT[ECODE]}($ECODE)&quot; &gt;&amp;2&#39;</span><span class=w> </span><span class=m>0</span>
<a id=__codelineno-2-18 name=__codelineno-2-18 href=#__codelineno-2-18></a><span class=nb>echo</span><span class=w> </span>-n<span class=w> </span><span class=s2>&quot;[statsgen] Locking: &quot;</span><span class=w> </span>&gt;<span class=p>&amp;</span><span class=m>2</span>
<a id=__codelineno-2-19 name=__codelineno-2-19 href=#__codelineno-2-19></a>
<a id=__codelineno-2-20 name=__codelineno-2-20 href=#__codelineno-2-20></a><span class=k>if</span><span class=w> </span>mkdir<span class=w> </span><span class=s2>&quot;</span><span class=si>${</span><span class=nv>LOCKDIR</span><span class=si>}</span><span class=s2>&quot;</span><span class=w> </span><span class=p>&amp;</span>&gt;/dev/null<span class=p>;</span><span class=w> </span><span class=k>then</span>
<a id=__codelineno-2-21 name=__codelineno-2-21 href=#__codelineno-2-21></a>
<a id=__codelineno-2-22 name=__codelineno-2-22 href=#__codelineno-2-22></a><span class=w> </span><span class=c1># lock succeeded, install signal handlers before storing the PID just in case</span>
<a id=__codelineno-2-23 name=__codelineno-2-23 href=#__codelineno-2-23></a><span class=w> </span><span class=c1># storing the PID fails</span>
<a id=__codelineno-2-24 name=__codelineno-2-24 href=#__codelineno-2-24></a><span class=w> </span><span class=nb>trap</span><span class=w> </span><span class=s1>&#39;ECODE=$?;</span>
<a id=__codelineno-2-25 name=__codelineno-2-25 href=#__codelineno-2-25></a><span class=s1> echo &quot;[statsgen] Removing lock. Exit: ${ETXT[ECODE]}($ECODE)&quot; &gt;&amp;2</span>
<a id=__codelineno-2-26 name=__codelineno-2-26 href=#__codelineno-2-26></a><span class=s1> rm -rf &quot;${LOCKDIR}&quot;&#39;</span><span class=w> </span><span class=m>0</span>
<a id=__codelineno-2-27 name=__codelineno-2-27 href=#__codelineno-2-27></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;</span><span class=nv>$$</span><span class=s2>&quot;</span><span class=w> </span>&gt;<span class=s2>&quot;</span><span class=si>${</span><span class=nv>PIDFILE</span><span class=si>}</span><span class=s2>&quot;</span>
<a id=__codelineno-2-28 name=__codelineno-2-28 href=#__codelineno-2-28></a><span class=w> </span><span class=c1># the following handler will exit the script upon receiving these signals</span>
<a id=__codelineno-2-29 name=__codelineno-2-29 href=#__codelineno-2-29></a><span class=w> </span><span class=c1># the trap on &quot;0&quot; (EXIT) from above will be triggered by this trap&#39;s &quot;exit&quot; command!</span>
<a id=__codelineno-2-30 name=__codelineno-2-30 href=#__codelineno-2-30></a><span class=w> </span><span class=nb>trap</span><span class=w> </span><span class=s1>&#39;echo &quot;[statsgen] Killed by a signal.&quot; &gt;&amp;2</span>
<a id=__codelineno-2-31 name=__codelineno-2-31 href=#__codelineno-2-31></a><span class=s1> exit ${ENO_RECVSIG}&#39;</span><span class=w> </span><span class=m>1</span><span class=w> </span><span class=m>2</span><span class=w> </span><span class=m>3</span><span class=w> </span><span class=m>15</span>
<a id=__codelineno-2-32 name=__codelineno-2-32 href=#__codelineno-2-32></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;success, installed signal handlers&quot;</span>
<a id=__codelineno-2-33 name=__codelineno-2-33 href=#__codelineno-2-33></a>
<a id=__codelineno-2-34 name=__codelineno-2-34 href=#__codelineno-2-34></a><span class=k>else</span>
<a id=__codelineno-2-35 name=__codelineno-2-35 href=#__codelineno-2-35></a>
<a id=__codelineno-2-36 name=__codelineno-2-36 href=#__codelineno-2-36></a><span class=w> </span><span class=c1># lock failed, check if the other PID is alive</span>
<a id=__codelineno-2-37 name=__codelineno-2-37 href=#__codelineno-2-37></a><span class=w> </span><span class=nv>OTHERPID</span><span class=o>=</span><span class=s2>&quot;</span><span class=k>$(</span>cat<span class=w> </span><span class=s2>&quot;</span><span class=si>${</span><span class=nv>PIDFILE</span><span class=si>}</span><span class=s2>&quot;</span><span class=k>)</span><span class=s2>&quot;</span>
<a id=__codelineno-2-38 name=__codelineno-2-38 href=#__codelineno-2-38></a>
<a id=__codelineno-2-39 name=__codelineno-2-39 href=#__codelineno-2-39></a><span class=w> </span><span class=c1># if cat isn&#39;t able to read the file, another instance is probably</span>
<a id=__codelineno-2-40 name=__codelineno-2-40 href=#__codelineno-2-40></a><span class=w> </span><span class=c1># about to remove the lock -- exit, we&#39;re *still* locked</span>
<a id=__codelineno-2-41 name=__codelineno-2-41 href=#__codelineno-2-41></a><span class=w> </span><span class=c1># Thanks to Grzegorz Wierzowiecki for pointing out this race condition on</span>
<a id=__codelineno-2-42 name=__codelineno-2-42 href=#__codelineno-2-42></a><span class=w> </span><span class=c1># http://wiki.grzegorz.wierzowiecki.pl/code:mutex-in-bash</span>
<a id=__codelineno-2-43 name=__codelineno-2-43 href=#__codelineno-2-43></a><span class=w> </span><span class=k>if</span><span class=w> </span><span class=o>[</span><span class=w> </span><span class=nv>$?</span><span class=w> </span>!<span class=o>=</span><span class=w> </span><span class=m>0</span><span class=w> </span><span class=o>]</span><span class=p>;</span><span class=w> </span><span class=k>then</span>
<a id=__codelineno-2-44 name=__codelineno-2-44 href=#__codelineno-2-44></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;lock failed, PID </span><span class=si>${</span><span class=nv>OTHERPID</span><span class=si>}</span><span class=s2> is active&quot;</span><span class=w> </span>&gt;<span class=p>&amp;</span><span class=m>2</span>
<a id=__codelineno-2-45 name=__codelineno-2-45 href=#__codelineno-2-45></a><span class=w> </span><span class=nb>exit</span><span class=w> </span><span class=si>${</span><span class=nv>ENO_LOCKFAIL</span><span class=si>}</span>
<a id=__codelineno-2-46 name=__codelineno-2-46 href=#__codelineno-2-46></a><span class=w> </span><span class=k>fi</span>
<a id=__codelineno-2-47 name=__codelineno-2-47 href=#__codelineno-2-47></a>
<a id=__codelineno-2-48 name=__codelineno-2-48 href=#__codelineno-2-48></a><span class=w> </span><span class=k>if</span><span class=w> </span>!<span class=w> </span><span class=nb>kill</span><span class=w> </span>-0<span class=w> </span><span class=nv>$OTHERPID</span><span class=w> </span><span class=p>&amp;</span>&gt;/dev/null<span class=p>;</span><span class=w> </span><span class=k>then</span>
<a id=__codelineno-2-49 name=__codelineno-2-49 href=#__codelineno-2-49></a><span class=w> </span><span class=c1># lock is stale, remove it and restart</span>
<a id=__codelineno-2-50 name=__codelineno-2-50 href=#__codelineno-2-50></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;removing stale lock of nonexistant PID </span><span class=si>${</span><span class=nv>OTHERPID</span><span class=si>}</span><span class=s2>&quot;</span><span class=w> </span>&gt;<span class=p>&amp;</span><span class=m>2</span>
<a id=__codelineno-2-51 name=__codelineno-2-51 href=#__codelineno-2-51></a><span class=w> </span>rm<span class=w> </span>-rf<span class=w> </span><span class=s2>&quot;</span><span class=si>${</span><span class=nv>LOCKDIR</span><span class=si>}</span><span class=s2>&quot;</span>
<a id=__codelineno-2-52 name=__codelineno-2-52 href=#__codelineno-2-52></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;[statsgen] restarting myself&quot;</span><span class=w> </span>&gt;<span class=p>&amp;</span><span class=m>2</span>
<a id=__codelineno-2-53 name=__codelineno-2-53 href=#__codelineno-2-53></a><span class=w> </span><span class=nb>exec</span><span class=w> </span><span class=s2>&quot;</span><span class=nv>$0</span><span class=s2>&quot;</span><span class=w> </span><span class=s2>&quot;</span><span class=nv>$@</span><span class=s2>&quot;</span>
<a id=__codelineno-2-54 name=__codelineno-2-54 href=#__codelineno-2-54></a><span class=w> </span><span class=k>else</span>
<a id=__codelineno-2-55 name=__codelineno-2-55 href=#__codelineno-2-55></a><span class=w> </span><span class=c1># lock is valid and OTHERPID is active - exit, we&#39;re locked!</span>
<a id=__codelineno-2-56 name=__codelineno-2-56 href=#__codelineno-2-56></a><span class=w> </span><span class=nb>echo</span><span class=w> </span><span class=s2>&quot;lock failed, PID </span><span class=si>${</span><span class=nv>OTHERPID</span><span class=si>}</span><span class=s2> is active&quot;</span><span class=w> </span>&gt;<span class=p>&amp;</span><span class=m>2</span>
<a id=__codelineno-2-57 name=__codelineno-2-57 href=#__codelineno-2-57></a><span class=w> </span><span class=nb>exit</span><span class=w> </span><span class=si>${</span><span class=nv>ENO_LOCKFAIL</span><span class=si>}</span>
<a id=__codelineno-2-58 name=__codelineno-2-58 href=#__codelineno-2-58></a><span class=w> </span><span class=k>fi</span>
<a id=__codelineno-2-59 name=__codelineno-2-59 href=#__codelineno-2-59></a>
<a id=__codelineno-2-60 name=__codelineno-2-60 href=#__codelineno-2-60></a><span class=k>fi</span>
</code></pre></div> <h2 id=related-links>Related links<a class=headerlink href=#related-links title="Permanent link">&para;</a></h2> <ul> <li><a href=http://mywiki.wooledge.org/BashFAQ/045>BashFAQ/045</a></li> <li><a href=http://wiki.grzegorz.wierzowiecki.pl/code:mutex-in-bash>Implementation of a shell locking utility</a></li> <li><a href=http://en.wikipedia.org/wiki/File_locking>Wikipedia article on File Locking</a>, including a discussion of potential <a href=http://en.wikipedia.org/wiki/File_locking#Problems>problems</a> with flock and certain versions of NFS.</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>