From c154a2096801851c1ec9588d30899603d605b519 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 8 May 2014 14:36:47 -0400 Subject: Hmm, this was sitting on my laptop --- public/bash-redirection.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 public/bash-redirection.md diff --git a/public/bash-redirection.md b/public/bash-redirection.md new file mode 100644 index 0000000..8da02b3 --- /dev/null +++ b/public/bash-redirection.md @@ -0,0 +1,50 @@ +Bash redirection +================ +--- +date: "2014-02-13" +--- + +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. + +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 `/dev/*` and `/proc/*` is interesting, but +beyond the scope of this article. + +Step 1: Pipes +------------- + +To quote the Bash manual: + + A 'pipeline' is a sequence of simple commands separated by one of the + control operators '|' or '|&'. + + The format for a pipeline is + [time [-p]] [!] COMMAND1 [ [| or |&] COMMAND2 ...] + +Now, `|&` is just shorthand for `2>&1 |`, the pipe part happens here, +but the `2>&1` part doesn't happen until step 2. + +First, if the command is part of a pipeline, the pipes are set up. +For every instance of the `|` metacharacter, Bash creates a pipe +(`pipe(3)`), and duplicates (`dup2(3)`) the write end of the pipe to +FD 1 of the process on the left side of the `|`, and duplicate the +read end of the pipe to FD 0 of the process on the right side. + +Step 2: Redirections +-------------------- + +*After* the initial FD 0 and FD 1 fiddling by pipes is done, Bash +looks at the redirections. **This means that redirections can +override pipes.** + +Redirections are read left-to-right, and are executed as they are +read, using `dup2(right-side, left-side)`. 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: + + cmd 2>&1 >file # stdout goes to file, stderr goes to stdout + cmd >file 2>&1 # both stdout and stderr go to file -- cgit v1.2.3