summaryrefslogtreecommitdiff
path: root/public/bash-redirection.html
blob: f846a61d5206d3038f89de2eb2a9fc294580cb95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Bash redirection — Luke T. Shumaker</title>
  <link rel="stylesheet" href="assets/style.css">
  <link rel="alternate" type="application/atom+xml" href="./index.atom" name="web log entries"/>
</head>
<body>
<header><a href="/">Luke T. Shumaker</a> » <a href=/blog>blog</a> » bash-redirection</header>
<article>
<h1 id="bash-redirection">Bash redirection</h1>
<p>Apparently, too many people don’t understand Bash redirection. They
might get the basic syntax, but they think of the process as
declarative; in Bourne-ish shells, it is procedural.</p>
<p>In Bash, streams are handled in terms of “file descriptors” of “FDs”.
FD 0 is stdin, FD 1 is stdout, and FD 2 is stderr. The equivalence (or
lack thereof) between using a numeric file descriptor, and using the
associated file in <code>/dev/*</code> and <code>/proc/*</code> is
interesting, but beyond the scope of this article.</p>
<h2 id="step-1-pipes">Step 1: Pipes</h2>
<p>To quote the Bash manual:</p>
<pre><code>A &#39;pipeline&#39; is a sequence of simple commands separated by one of the
control operators &#39;|&#39; or &#39;|&amp;&#39;.

   The format for a pipeline is
     [time [-p]] [!] COMMAND1 [ [| or |&amp;] COMMAND2 ...]</code></pre>
<p>Now, <code>|&amp;</code> is just shorthand for
<code>2&gt;&amp;1 |</code>, the pipe part happens here, but the
<code>2&gt;&amp;1</code> part doesn’t happen until step 2.</p>
<p>First, if the command is part of a pipeline, the pipes are set up.
For every instance of the <code>|</code> metacharacter, Bash creates a
pipe (<code>pipe(3)</code>), and duplicates (<code>dup2(3)</code>) the
write end of the pipe to FD 1 of the process on the left side of the
<code>|</code>, and duplicate the read end of the pipe to FD 0 of the
process on the right side.</p>
<h2 id="step-2-redirections">Step 2: Redirections</h2>
<p><em>After</em> the initial FD 0 and FD 1 fiddling by pipes is done,
Bash looks at the redirections. <strong>This means that redirections can
override pipes.</strong></p>
<p>Redirections are read left-to-right, and are executed as they are
read, using <code>dup2(right-side, left-side)</code>. This is where most
of the confusion comes from, people think of them as declarative, which
leads to them doing the first of these, when they mean to do the
second:</p>
<pre><code>cmd 2&gt;&amp;1 &gt;file # stdout goes to file, stderr goes to stdout
cmd &gt;file 2&gt;&amp;1 # both stdout and stderr go to file</code></pre>

</article>
<footer>
  <aside class="sponsor"><p>I'd love it if you <a class="em"
      href="/sponsor/">sponsored me</a>.  It will allow me to continue
      my work on the GNU/Linux ecosystem.  Thanks!</p></aside>

<p>The content of this page is Copyright © 2014 <a href="mailto:lukeshu@lukeshu.com">Luke T. Shumaker</a>.</p>
<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a> license.</p>
</footer>
</body>
</html>