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

105 lines
64 KiB
HTML

<!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-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script> <label class="md-header__button md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg> </label> <div class=md-search data-md-component=search role=dialog> <label class=md-search__overlay for=__search></label> <div class=md-search__inner role=search> <form class=md-search__form name=search> <input type=text class=md-search__input name=query aria-label=Search placeholder=Search autocapitalize=off autocorrect=off autocomplete=off spellcheck=false data-md-component=search-query required> <label class="md-search__icon md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg> </label> <nav class=md-search__options aria-label=Search> <button type=reset class="md-search__icon md-icon" title=Clear aria-label=Clear tabindex=-1> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg> </button> </nav> <div class=md-search__suggest data-md-component=search-suggest></div> </form> <div class=md-search__output> <div class=md-search__scrollwrap tabindex=0 data-md-scrollfix> <div class=md-search-result data-md-component=search-result> <div class=md-search-result__meta> Initializing search </div> <ol class=md-search-result__list role=presentation></ol> </div> </div> </div> </div> </div> <div class=md-header__source> <a href=https://github.com/flokoe/bash-hackers-wiki title="Go to repository" class=md-source data-md-component=source> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 496 512"><!-- Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8M97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </div> <div class=md-source__repository> flokoe/bash-hackers-wiki </div> </a> </div> </nav> </header> <div class=md-container data-md-component=container> <nav class=md-tabs aria-label=Tabs data-md-component=tabs> <div class=md-grid> <ul class=md-tabs__list> <li class=md-tabs__item> <a href=../.. class=md-tabs__link> Start </a> </li> <li class=md-tabs__item> <a href=../../commands/classictest/ class=md-tabs__link> Commands </a> </li> <li class=md-tabs__item> <a href=../../dict/directory/ class=md-tabs__link> Dict </a> </li> <li class="md-tabs__item md-tabs__item--active"> <a href=../calculate-dc/ class=md-tabs__link> Howto </a> </li> <li class=md-tabs__item> <a href=../../internals/shell_options/ class=md-tabs__link> Internals </a> </li> <li class=md-tabs__item> <a href=../../misc/bashphorisms/ class=md-tabs__link> Misc </a> </li> <li class=md-tabs__item> <a href=../../scripting/bashbehaviour/ class=md-tabs__link> Scripting </a> </li> <li class=md-tabs__item> <a href=../../snipplets/ class=md-tabs__link> Snipplets </a> </li> <li class=md-tabs__item> <a href=../../syntax/arith_expr/ class=md-tabs__link> Syntax </a> </li> <li class=md-tabs__item> <a href=../../tags/ class=md-tabs__link> Tags </a> </li> </ul> </div> </nav> <main class=md-main data-md-component=main> <div class="md-main__inner md-grid"> <div class="md-sidebar md-sidebar--primary" data-md-component=sidebar data-md-type=navigation> <div class=md-sidebar__scrollwrap> <div class=md-sidebar__inner> <nav class="md-nav md-nav--primary md-nav--lifted" aria-label=Navigation data-md-level=0> <label class=md-nav__title for=__drawer> <a href=../.. title="The Bash Hackers Wiki" class="md-nav__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> The Bash Hackers Wiki </label> <div class=md-nav__source> <a href=https://github.com/flokoe/bash-hackers-wiki title="Go to repository" class=md-source data-md-component=source> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 496 512"><!-- Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8M97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </div> <div class=md-source__repository> flokoe/bash-hackers-wiki </div> </a> </div> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../.. class=md-nav__link> <span class=md-ellipsis> Start </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_2> <label class=md-nav__link for=__nav_2 id=__nav_2_label tabindex=0> <span class=md-ellipsis> Commands </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_2_label aria-expanded=false> <label class=md-nav__title for=__nav_2> <span class="md-nav__icon md-icon"></span> Commands </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../commands/classictest/ class=md-nav__link> <span class=md-ellipsis> The classic test command </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_2_2> <label class=md-nav__link for=__nav_2_2 id=__nav_2_2_label tabindex=0> <span class=md-ellipsis> Builtin </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_2_2_label aria-expanded=false> <label class=md-nav__title for=__nav_2_2> <span class="md-nav__icon md-icon"></span> Builtin </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../commands/builtin/caller/ class=md-nav__link> <span class=md-ellipsis> The caller builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/cd/ class=md-nav__link> <span class=md-ellipsis> The cd builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/declare/ class=md-nav__link> <span class=md-ellipsis> The declare builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/echo/ class=md-nav__link> <span class=md-ellipsis> The echo builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/eval/ class=md-nav__link> <span class=md-ellipsis> The eval builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/exec/ class=md-nav__link> <span class=md-ellipsis> The exec builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/exit/ class=md-nav__link> <span class=md-ellipsis> The exit builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/export/ class=md-nav__link> <span class=md-ellipsis> The export builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/kill/ class=md-nav__link> <span class=md-ellipsis> The kill builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/let/ class=md-nav__link> <span class=md-ellipsis> The let builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/local/ class=md-nav__link> <span class=md-ellipsis> The local builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/mapfile/ class=md-nav__link> <span class=md-ellipsis> The mapfile builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/printf/ class=md-nav__link> <span class=md-ellipsis> The printf command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/read/ class=md-nav__link> <span class=md-ellipsis> The read builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/readonly/ class=md-nav__link> <span class=md-ellipsis> The readonly builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/return/ class=md-nav__link> <span class=md-ellipsis> The return builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/set/ class=md-nav__link> <span class=md-ellipsis> The set builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/shift/ class=md-nav__link> <span class=md-ellipsis> The shift builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/shopt/ class=md-nav__link> <span class=md-ellipsis> The shopt builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/trap/ class=md-nav__link> <span class=md-ellipsis> The trap builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/unset/ class=md-nav__link> <span class=md-ellipsis> The unset builtin command </span> </a> </li> <li class=md-nav__item> <a href=../../commands/builtin/wait/ class=md-nav__link> <span class=md-ellipsis> The wait builtin command </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_3> <label class=md-nav__link for=__nav_3 id=__nav_3_label tabindex=0> <span class=md-ellipsis> Dict </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_3_label aria-expanded=false> <label class=md-nav__title for=__nav_3> <span class="md-nav__icon md-icon"></span> Dict </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../dict/directory/ class=md-nav__link> <span class=md-ellipsis> Directory </span> </a> </li> <li class=md-nav__item> <a href=../../dict/end_of_options/ class=md-nav__link> <span class=md-ellipsis> End of Options </span> </a> </li> <li class=md-nav__item> <a href=../../dict/exit_status/ class=md-nav__link> <span class=md-ellipsis> Exit Status </span> </a> </li> <li class=md-nav__item> <a href=../../dict/file/ class=md-nav__link> <span class=md-ellipsis> File </span> </a> </li> <li class=md-nav__item> <a href=../../dict/filetimes/ class=md-nav__link> <span class=md-ellipsis> File timestamp </span> </a> </li> <li class=md-nav__item> <a href=../../dict/globbing/ class=md-nav__link> <span class=md-ellipsis> Globbing </span> </a> </li> <li class=md-nav__item> <a href=../../dict/hardlink/ class=md-nav__link> <span class=md-ellipsis> Hardlink </span> </a> </li> <li class=md-nav__item> <a href=../../dict/interpreter_directive/ class=md-nav__link> <span class=md-ellipsis> Interpreter Directive </span> </a> </li> <li class=md-nav__item> <a href=../../dict/parameter/ class=md-nav__link> <span class=md-ellipsis> Parameter </span> </a> </li> <li class=md-nav__item> <a href=../../dict/posix/ class=md-nav__link> <span class=md-ellipsis> POSIX </span> </a> </li> <li class=md-nav__item> <a href=../../dict/shell/ class=md-nav__link> <span class=md-ellipsis> Shell </span> </a> </li> <li class=md-nav__item> <a href=../../dict/special_file/ class=md-nav__link> <span class=md-ellipsis> Special file </span> </a> </li> <li class=md-nav__item> <a href=../../dict/symlink/ class=md-nav__link> <span class=md-ellipsis> Symlink </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_4 checked> <label class=md-nav__link for=__nav_4 id=__nav_4_label tabindex> <span class=md-ellipsis> Howto </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_4_label aria-expanded=true> <label class=md-nav__title for=__nav_4> <span class="md-nav__icon md-icon"></span> Howto </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../calculate-dc/ class=md-nav__link> <span class=md-ellipsis> Calculating with dc </span> </a> </li> <li class=md-nav__item> <a href=../collapsing_functions/ class=md-nav__link> <span class=md-ellipsis> Collapsing Functions </span> </a> </li> <li class=md-nav__item> <a href=../conffile/ class=md-nav__link> <span class=md-ellipsis> Config files for your script </span> </a> </li> <li class=md-nav__item> <a href=../dissectabadoneliner/ class=md-nav__link> <span class=md-ellipsis> Dissect a bad oneliner </span> </a> </li> <li class=md-nav__item> <a href=../edit-ed/ class=md-nav__link> <span class=md-ellipsis> Editing files via scripts with ed </span> </a> </li> <li class=md-nav__item> <a href=../getopts_tutorial/ class=md-nav__link> <span class=md-ellipsis> Small getopts tutorial </span> </a> </li> <li class="md-nav__item md-nav__item--active"> <input class="md-nav__toggle md-toggle" type=checkbox id=__toc> <label class="md-nav__link md-nav__link--active" for=__toc> <span class=md-ellipsis> Lock your script (against parallel execution) </span> <span class="md-nav__icon md-icon"></span> </label> <a href=./ class="md-nav__link md-nav__link--active"> <span class=md-ellipsis> Lock your script (against parallel execution) </span> </a> <nav class="md-nav md-nav--secondary" aria-label="Table of contents"> <label class=md-nav__title for=__toc> <span class="md-nav__icon md-icon"></span> Table of contents </label> <ul class=md-nav__list data-md-component=toc data-md-scrollfix> <li class=md-nav__item> <a href=#why-lock class=md-nav__link> <span class=md-ellipsis> Why lock? </span> </a> <nav class=md-nav aria-label="Why lock?"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#other-special-locking-tools class=md-nav__link> <span class=md-ellipsis> Other, special locking tools </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#choose-the-locking-method class=md-nav__link> <span class=md-ellipsis> Choose the locking method </span> </a> </li> <li class=md-nav__item> <a href=#an-example class=md-nav__link> <span class=md-ellipsis> An example </span> </a> </li> <li class=md-nav__item> <a href=#related-links class=md-nav__link> <span class=md-ellipsis> Related links </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../pax/ class=md-nav__link> <span class=md-ellipsis> pax - the POSIX archiver </span> </a> </li> <li class=md-nav__item> <a href=../redirection_tutorial/ class=md-nav__link> <span class=md-ellipsis> Illustrated Redirection Tutorial </span> </a> </li> <li class=md-nav__item> <a href=../testing-your-scripts/ class=md-nav__link> <span class=md-ellipsis> Testing your scripts </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_5> <label class=md-nav__link for=__nav_5 id=__nav_5_label tabindex=0> <span class=md-ellipsis> Internals </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_5_label aria-expanded=false> <label class=md-nav__title for=__nav_5> <span class="md-nav__icon md-icon"></span> Internals </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../internals/shell_options/ class=md-nav__link> <span class=md-ellipsis> List of shell options </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_6> <label class=md-nav__link for=__nav_6 id=__nav_6_label tabindex=0> <span class=md-ellipsis> Misc </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_6_label aria-expanded=false> <label class=md-nav__title for=__nav_6> <span class="md-nav__icon md-icon"></span> Misc </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../misc/bashphorisms/ class=md-nav__link> <span class=md-ellipsis> The Bashphorisms </span> </a> </li> <li class=md-nav__item> <a href=../../misc/readthesourceluke/ class=md-nav__link> <span class=md-ellipsis> Readthesourceluke </span> </a> </li> <li class=md-nav__item> <a href=../../misc/shell_humor/ class=md-nav__link> <span class=md-ellipsis> Shell Humor </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_7> <label class=md-nav__link for=__nav_7 id=__nav_7_label tabindex=0> <span class=md-ellipsis> Scripting </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_7_label aria-expanded=false> <label class=md-nav__title for=__nav_7> <span class="md-nav__icon md-icon"></span> Scripting </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../scripting/bashbehaviour/ class=md-nav__link> <span class=md-ellipsis> Bash's behaviour </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/bashchanges/ class=md-nav__link> <span class=md-ellipsis> Bash changes </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/basics/ class=md-nav__link> <span class=md-ellipsis> The basics of shell scripting </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/debuggingtips/ class=md-nav__link> <span class=md-ellipsis> Debugging a script </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/newbie_traps/ class=md-nav__link> <span class=md-ellipsis> Beginner Mistakes </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/nonportable/ class=md-nav__link> <span class=md-ellipsis> Portability talk </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/obsolete/ class=md-nav__link> <span class=md-ellipsis> Obsolete and deprecated syntax </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/posparams/ class=md-nav__link> <span class=md-ellipsis> Handling positional parameters </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/processtree/ class=md-nav__link> <span class=md-ellipsis> Bash and the process tree </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/style/ class=md-nav__link> <span class=md-ellipsis> Scripting with style </span> </a> </li> <li class=md-nav__item> <a href=../../scripting/terminalcodes/ class=md-nav__link> <span class=md-ellipsis> Terminal codes (ANSI/VT100) introduction </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_8> <label class=md-nav__link for=__nav_8 id=__nav_8_label tabindex=0> <span class=md-ellipsis> Snipplets </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_8_label aria-expanded=false> <label class=md-nav__title for=__nav_8> <span class="md-nav__icon md-icon"></span> Snipplets </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../snipplets/ class=md-nav__link> <span class=md-ellipsis> Small code snipplets </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/add_color_to_your_scripts/ class=md-nav__link> <span class=md-ellipsis> Add Color to your scripts </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/awkcsv/ class=md-nav__link> <span class=md-ellipsis> Using awk to deal with CSV that uses quoted/unquoted delimiters </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/filesize/ class=md-nav__link> <span class=md-ellipsis> Show size of a file </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/kill_bg_job_without_message/ class=md-nav__link> <span class=md-ellipsis> Kill a background job without a message </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/largestfile/ class=md-nav__link> <span class=md-ellipsis> Get largest file </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/pause_command/ class=md-nav__link> <span class=md-ellipsis> Pausing a script (like MSDOS pause command) </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/prargs/ class=md-nav__link> <span class=md-ellipsis> Print argument list for testing </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/print_horizontal_line/ class=md-nav__link> <span class=md-ellipsis> Print a horizontal line </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/rndstr/ class=md-nav__link> <span class=md-ellipsis> Print a random string or select random elements </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/screen_saverestore/ class=md-nav__link> <span class=md-ellipsis> Save and restore terminal/screen content </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/ssh_fetchkeys/ class=md-nav__link> <span class=md-ellipsis> Fetching SSH hostkeys without interaction </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/ssh_local_var/ class=md-nav__link> <span class=md-ellipsis> Run some bash commands with SSH remotely using local variables </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/wrapperargs/ class=md-nav__link> <span class=md-ellipsis> Generate code with own arguments properly quoted </span> </a> </li> <li class=md-nav__item> <a href=../../snipplets/xclip/ class=md-nav__link> <span class=md-ellipsis> X-Clipboard on Commandline </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_9> <label class=md-nav__link for=__nav_9 id=__nav_9_label tabindex=0> <span class=md-ellipsis> Syntax </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_9_label aria-expanded=false> <label class=md-nav__title for=__nav_9> <span class="md-nav__icon md-icon"></span> Syntax </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../syntax/arith_expr/ class=md-nav__link> <span class=md-ellipsis> Arithmetic expressions </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/arrays/ class=md-nav__link> <span class=md-ellipsis> Arrays </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/basicgrammar/ class=md-nav__link> <span class=md-ellipsis> Basic grammar rules of Bash </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/pattern/ class=md-nav__link> <span class=md-ellipsis> Patterns and pattern matching </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/pe/ class=md-nav__link> <span class=md-ellipsis> Parameter expansion </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/quoting/ class=md-nav__link> <span class=md-ellipsis> Quotes and escaping </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/redirection/ class=md-nav__link> <span class=md-ellipsis> Redirection </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/shellvars/ class=md-nav__link> <span class=md-ellipsis> Special parameters and shell variables </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/words/ class=md-nav__link> <span class=md-ellipsis> Words... </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_9_10> <label class=md-nav__link for=__nav_9_10 id=__nav_9_10_label tabindex=0> <span class=md-ellipsis> Ccmd </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_9_10_label aria-expanded=false> <label class=md-nav__title for=__nav_9_10> <span class="md-nav__icon md-icon"></span> Ccmd </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../syntax/ccmd/arithmetic_eval/ class=md-nav__link> <span class=md-ellipsis> Arithmetic evaluation (command) </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/c_for/ class=md-nav__link> <span class=md-ellipsis> The C-style for-loop </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/case/ class=md-nav__link> <span class=md-ellipsis> The case statement </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/classic_for/ class=md-nav__link> <span class=md-ellipsis> The classic for-loop </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/conditional_expression/ class=md-nav__link> <span class=md-ellipsis> The conditional expression </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/grouping_plain/ class=md-nav__link> <span class=md-ellipsis> Grouping commands </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/grouping_subshell/ class=md-nav__link> <span class=md-ellipsis> Grouping commands in a subshell </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/if_clause/ class=md-nav__link> <span class=md-ellipsis> The if-clause </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/intro/ class=md-nav__link> <span class=md-ellipsis> Bash compound commands </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/until_loop/ class=md-nav__link> <span class=md-ellipsis> The until loop </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/user_select/ class=md-nav__link> <span class=md-ellipsis> User selections </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/ccmd/while_loop/ class=md-nav__link> <span class=md-ellipsis> The while-loop </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_9_11> <label class=md-nav__link for=__nav_9_11 id=__nav_9_11_label tabindex=0> <span class=md-ellipsis> Expansion </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_9_11_label aria-expanded=false> <label class=md-nav__title for=__nav_9_11> <span class="md-nav__icon md-icon"></span> Expansion </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../syntax/expansion/arith/ class=md-nav__link> <span class=md-ellipsis> Arithmetic expansion </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/expansion/brace/ class=md-nav__link> <span class=md-ellipsis> Brace expansion </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/expansion/cmdsubst/ class=md-nav__link> <span class=md-ellipsis> Command substitution </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/expansion/globs/ class=md-nav__link> <span class=md-ellipsis> Pathname expansion (globbing) </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/expansion/intro/ class=md-nav__link> <span class=md-ellipsis> Expansions and substitutions </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/expansion/proc_subst/ class=md-nav__link> <span class=md-ellipsis> Process substitution </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/expansion/tilde/ class=md-nav__link> <span class=md-ellipsis> Tilde expansion </span> </a> </li> <li class=md-nav__item> <a href=../../syntax/expansion/wordsplit/ class=md-nav__link> <span class=md-ellipsis> Word splitting </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_9_12> <label class=md-nav__link for=__nav_9_12 id=__nav_9_12_label tabindex=0> <span class=md-ellipsis> Grammar </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_9_12_label aria-expanded=false> <label class=md-nav__title for=__nav_9_12> <span class="md-nav__icon md-icon"></span> Grammar </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../syntax/grammar/parser_exec/ class=md-nav__link> <span class=md-ellipsis> Parser exec </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle " type=checkbox id=__nav_9_13> <label class=md-nav__link for=__nav_9_13 id=__nav_9_13_label tabindex=0> <span class=md-ellipsis> Keywords </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_9_13_label aria-expanded=false> <label class=md-nav__title for=__nav_9_13> <span class="md-nav__icon md-icon"></span> Keywords </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../syntax/keywords/coproc/ class=md-nav__link> <span class=md-ellipsis> The coproc keyword </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../tags/ class=md-nav__link> <span class=md-ellipsis> Tags </span> </a> </li> </ul> </nav> </div> </div> </div> <div class="md-sidebar md-sidebar--secondary" data-md-component=sidebar data-md-type=toc> <div class=md-sidebar__scrollwrap> <div class=md-sidebar__inner> <nav class="md-nav md-nav--secondary" aria-label="Table of contents"> <label class=md-nav__title for=__toc> <span class="md-nav__icon md-icon"></span> Table of contents </label> <ul class=md-nav__list data-md-component=toc data-md-scrollfix> <li class=md-nav__item> <a href=#why-lock class=md-nav__link> <span class=md-ellipsis> Why lock? </span> </a> <nav class=md-nav aria-label="Why lock?"> <ul class=md-nav__list> <li class=md-nav__item> <a href=#other-special-locking-tools class=md-nav__link> <span class=md-ellipsis> Other, special locking tools </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=#choose-the-locking-method class=md-nav__link> <span class=md-ellipsis> Choose the locking method </span> </a> </li> <li class=md-nav__item> <a href=#an-example class=md-nav__link> <span class=md-ellipsis> An example </span> </a> </li> <li class=md-nav__item> <a href=#related-links class=md-nav__link> <span class=md-ellipsis> Related links </span> </a> </li> </ul> </nav> </div> </div> </div> <div class=md-content data-md-component=content> <article class="md-content__inner md-typeset"> <nav class=md-tags> <a href=../../tags/#bash class=md-tag>bash</a> <a href=../../tags/#shell class=md-tag>shell</a> <a href=../../tags/#scripting class=md-tag>scripting</a> <a href=../../tags/#mutex class=md-tag>mutex</a> <a href=../../tags/#locking class=md-tag>locking</a> <a href=../../tags/#run-control class=md-tag>run-control</a> </nav> <a href=https://github.com/flokoe/bash-hackers-wiki/edit/main/docs/howto/mutex.md title="Edit this page" class="md-content__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4zm10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1z"/></svg> </a> <a href=https://github.com/flokoe/bash-hackers-wiki/raw/main/docs/howto/mutex.md title="View source of this page" class="md-content__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M17 18c.56 0 1 .44 1 1s-.44 1-1 1-1-.44-1-1 .44-1 1-1m0-3c-2.73 0-5.06 1.66-6 4 .94 2.34 3.27 4 6 4s5.06-1.66 6-4c-.94-2.34-3.27-4-6-4m0 6.5a2.5 2.5 0 0 1-2.5-2.5 2.5 2.5 0 0 1 2.5-2.5 2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5M9.27 20H6V4h7v5h5v4.07c.7.08 1.36.25 2 .49V8l-6-6H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h4.5a8.2 8.2 0 0 1-1.23-2"/></svg> </a> <h1 id=lock-your-script-against-parallel-execution>Lock your script (against parallel execution)<a class=headerlink href=#lock-your-script-against-parallel-execution title="Permanent link">&para;</a></h1> <h2 id=why-lock>Why lock?<a class=headerlink href=#why-lock title="Permanent link">&para;</a></h2> <p>Sometimes there's a need to ensure only one copy of a script runs, i.e prevent two or more copies running simultaneously. Imagine an important cronjob doing something very important, which will fail or corrupt data if two copies of the called program were to run at the same time. To prevent this, a form of <code>MUTEX</code> (<strong>mutual exclusion</strong>) lock is needed.</p> <p>The basic procedure is simple: The script checks if a specific condition (locking) is present at startup, if yes, it's locked - the scipt doesn't start.</p> <p>This article describes locking with common UNIX&reg; tools. There are other special locking tools available, But they're not standardized, or worse yet, you can't be sure they're present when you want to run your scripts. <strong>A tool designed for specifically for this purpose does the job much better than general purpose code.</strong></p> <h3 id=other-special-locking-tools>Other, special locking tools<a class=headerlink href=#other-special-locking-tools title="Permanent link">&para;</a></h3> <p>As told above, a special tool for locking is the preferred solution. Race conditions are avoided, as is the need to work around specific limits.</p> <ul> <li><code>flock</code>: <a href=http://www.kernel.org/pub/software/utils/script/flock/ >http://www.kernel.org/pub/software/utils/script/flock/</a></li> <li><code>solo</code>: <a href=http://timkay.com/solo/ >http://timkay.com/solo/</a></li> </ul> <h2 id=choose-the-locking-method>Choose the locking method<a class=headerlink href=#choose-the-locking-method title="Permanent link">&para;</a></h2> <p>The best way to set a global lock condition is the UNIX&reg; filesystem. Variables aren't enough, as each process has its own private variable space, but the filesystem is global to all processes (yes, I know about chroots, namespaces, ... special case). You can "set" several things in the filesystem that can be used as locking indicator:</p> <ul> <li>create files</li> <li>update file timestamps</li> <li>create directories</li> </ul> <p>To create a file or set a file timestamp, usually the command touch is used. The following problem is implied: A locking mechanism checks for the existance of the lockfile, if no lockfile exists, it creates one and continues. Those are <strong>two separate steps</strong>! That means it's <strong>not an atomic operation</strong>. There's a small amount of time between checking and creating, where another instance of the same script could perform locking (because when it checked, the lockfile wasn't there)! In that case you would have 2 instances of the script running, both thinking they are succesfully locked, and can operate without colliding. Setting the timestamp is similar: One step to check the timespamp, a second step to set the timestamp.</p> <p><wrap center round tip 60%> <u><strong>Conclusion:</strong></u> We need an operation that does the check and the locking in one step. </wrap></p> <p>A simple way to get that is to create a <strong>lock directory</strong> - with the mkdir command. It will:</p> <div class=highlight><pre><span></span><code> * create a given directory only if it does not exist, and set a successful exit code
* 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 7, 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 7, 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>