bash-hackers-wiki/scripting/processtree/index.html

56 lines
52 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/scripting/processtree/ rel=canonical><link href=../posparams/ rel=prev><link href=../style/ rel=next><link rel=icon href=../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.5.44"><title>Bash and the process tree - 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=#bash-and-the-process-tree 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> Bash and the process tree </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=matchMe
</code></pre></div> <p>Common system variables like <a href=../../syntax/shellvars/#PATH>PATH</a> or <a href=../../syntax/shellvars/#HOME>HOME</a> are usually part of the environment (as set by login scripts or programs).</p> <h2 id=executing-programs>Executing programs<a class=headerlink href=#executing-programs title="Permanent link">&para;</a></h2> <p>All the diagrams of the process tree use names like "<code>xterm</code>" or "<code>bash</code>", but that's just to make it easier to understand what's going on, it doesn't mean those processes are actually executed.</p> <p>Let's take a short look at what happens when you "execute a program" from the Bash prompt, a program like "ls":</p> <div class=highlight><pre><span></span><code>$ ls
</code></pre></div> <p>Bash will now perform <strong>two steps</strong>:</p> <ul> <li>It will make a copy of itself</li> <li>The copy will replace itself with the "ls" program</li> </ul> <p>The copy of Bash will inherit the environment from the "main Bash" process: All environment variables will also be copied to the new process. This step is called <strong>forking</strong>.</p> <p>For a short moment, you have a process tree that might look like this...</p> <div class=highlight><pre><span></span><code>xterm ----- bash ----- bash(copy)
</code></pre></div> <p>...and after the "second Bash" (the copy) replaces itself with the <code>ls</code> program (the copy execs it), it might look like</p> <div class=highlight><pre><span></span><code>xterm ----- bash ----- ls
</code></pre></div> <p>If everything was okay, the two steps resulted in one program being run. The copy of the environment from the first step (forking) becomes the environment for the final running program (in this case, <code>ls</code>).</p> <p><u><strong>What is so important about it?</strong></u> In our example, what the program <code>ls</code> does inside its own environment, it can't affect the environment of its parent process (in this case, <code>bash</code>). The environment was copied when ls was executed. Nothing is "copied back" to the parent environment when <code>ls</code> terminates.</p> <h2 id=bash-playing-with-pipes>Bash playing with pipes<a class=headerlink href=#bash-playing-with-pipes title="Permanent link">&para;</a></h2> <p>Pipes are a very powerful tool. You can connect the output of one process to the input of another process. We won't delve into piping at this point, we just want to see how it looks in the process tree. Again, we execute some commands, this time, we'll run <code>ls</code> and <code>grep</code>:</p> <div class=highlight><pre><span></span><code>$ ls | grep myfile
</code></pre></div> <p>It results in a tree like this:</p> <div class=highlight><pre><span></span><code> +-- ls
xterm ----- bash --|
+-- grep
</code></pre></div> <p>Note once again, <code>ls</code> can't influence the <code>grep</code> environment, <code>grep</code> can't influence the <code>ls</code> environment, and neither <code>grep</code> nor <code>ls</code> can influence the <code>bash</code> environment.</p> <p><u><strong>How is that related to shell programming?!?</strong></u></p> <p>Well, imagine some Bash code that reads data from a pipe. For example, the internal command <code>read</code>, which reads data from <em>stdin</em> and puts it into a variable. We run it in a loop here to count input lines:</p> <div class=highlight><pre><span></span><code>counter=0
cat /etc/passwd | while read; do ((counter++)); done
echo &quot;Lines: $counter&quot;
</code></pre></div> <p>What? It's 0? Yes! The number of lines might not be 0, but the variable <code>$counter</code> still is 0. Why? Remember the diagram from above? Rewriting it a bit, we have:</p> <div class=highlight><pre><span></span><code> +-- cat /etc/passwd
xterm ----- bash --|
+-- bash (while read; do ((counter++)); done)
</code></pre></div> <p>See the relationship? The forked Bash process will count the lines like a charm. It will also set the variable <code>counter</code> as directed. But if everything ends, this extra process will be terminated - <strong>your "counter" variable is gone.</strong> You see a 0 because in the main shell it was 0, and wasn't changed by the child process!</p> <p><u><strong>So, how do we count the lines?</strong></u> Easy: <strong>Avoid the subshell.</strong> The details don't matter, the important thing is the shell that sets the counter must be the "main shell". For example:</p> <div class=highlight><pre><span></span><code>counter=0
while read; do ((counter++)); done &lt;/etc/passwd
echo &quot;Lines: $counter&quot;
</code></pre></div> <p>It's nearly self-explanatory. The <code>while</code> loop runs in the <strong>current shell</strong>, the counter is incremented in the <strong>current shell</strong>, everything vital happens in the <strong>current shell</strong>, also the <code>read</code> command sets the variable <code>REPLY</code> (the default if nothing is given), though we don't use it here.</p> <h2 id=actions-that-create-a-subshell>Actions that create a subshell<a class=headerlink href=#actions-that-create-a-subshell title="Permanent link">&para;</a></h2> <p>Bash creates <strong>subshells</strong> or <strong>subprocesses</strong> on various actions it performs:</p> <h3 id=executing-commands>Executing commands<a class=headerlink href=#executing-commands title="Permanent link">&para;</a></h3> <p>As shown above, Bash will create subprocesses everytime it executes commands. That's nothing new.</p> <p>But if your command is a subprocess that sets variables you want to use in your main script, that won't work.</p> <p>For exactly this purpose, there's the <code>source</code> command (also: the <em>dot</em> <code>.</code> command). Source doesn't execute the script, it imports the other script's code into the current shell:</p> <div class=highlight><pre><span></span><code>source ./myvariables.sh
# equivalent to:
. ./myvariables.sh
</code></pre></div> <h3 id=pipes>Pipes<a class=headerlink href=#pipes title="Permanent link">&para;</a></h3> <p>The last big section was about pipes, so no example here.</p> <h3 id=explicit-subshell>Explicit subshell<a class=headerlink href=#explicit-subshell title="Permanent link">&para;</a></h3> <p>If you group commands by enclosing them in parentheses, these commands are run inside a subshell:</p> <div class=highlight><pre><span></span><code>(echo PASSWD follows; cat /etc/passwd; echo GROUP follows; cat /etc/group) &gt;output.txt
</code></pre></div> <h3 id=command-substitution>Command substitution<a class=headerlink href=#command-substitution title="Permanent link">&para;</a></h3> <p>With <a href=../../syntax/expansion/cmdsubst/ >command substitution</a> you re-use the output of another command as text in your command line, for example to set a variable. The other command is run in a subshell:</p> <div class=highlight><pre><span></span><code>number_of_users=$(cat /etc/passwd | wc -l)
</code></pre></div> <p>Note that, in this example, a second subshell was created by using a pipe in the command substitution:</p> <div class=highlight><pre><span></span><code> +-- cat /etc/passwd
xterm ----- bash ----- bash (cmd. subst.) --|
+-- wc -l
</code></pre></div> <div class="admonition warning"> <p class=admonition-title>FIXME</p> <p>to be continued</p> </div> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date">November 13, 2024</span> </span> <span class=md-source-file__fact> <span class=md-icon title=Created> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M14.47 15.08 11 13V7h1.5v5.25l3.08 1.83c-.41.28-.79.62-1.11 1m-1.39 4.84c-.36.05-.71.08-1.08.08-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8c0 .37-.03.72-.08 1.08.69.1 1.33.32 1.92.64.1-.56.16-1.13.16-1.72 0-5.5-4.5-10-10-10S2 6.5 2 12s4.47 10 10 10c.59 0 1.16-.06 1.72-.16-.32-.59-.54-1.23-.64-1.92M18 15v3h-3v2h3v3h2v-3h3v-2h-3v-3z"/></svg> </span> <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>