aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorartemis <faith@faithanalog.com>2021-09-23 04:17:04 -0700
committerGitHub <noreply@github.com>2021-09-23 07:17:04 -0400
commitdfe84da074ac14d2e0e036fdfe7609e0f5bfe687 (patch)
tree19b5b4ba2a9532595059640979af496a6f92fb8e
parente668250e16d7019ff61a2d4684f6d8b1bb3b4f3f (diff)
downloadxesite-dfe84da074ac14d2e0e036fdfe7609e0f5bfe687.tar.xz
xesite-dfe84da074ac14d2e0e036fdfe7609e0f5bfe687.zip
clarify some language; insert spaces in args to confuse beginners less (#400)
* clarify some language; insert spaces in args to confuse beginners less * fix 2>&1 footgun, explain it and how to avoid it * add cadence and AstroSnail to credits
-rw-r--r--blog/fun-with-redirection-2021-09-22.markdown68
1 files changed, 50 insertions, 18 deletions
diff --git a/blog/fun-with-redirection-2021-09-22.markdown b/blog/fun-with-redirection-2021-09-22.markdown
index df7b065..0757e8e 100644
--- a/blog/fun-with-redirection-2021-09-22.markdown
+++ b/blog/fun-with-redirection-2021-09-22.markdown
@@ -60,7 +60,7 @@ use the `cut` command to select that small subset from each line, and you can
feed the `cut` command's standard input using the `<` operator:
```console
-$ cut -d' ' -f2 < uname.txt
+$ cut -d ' ' -f 2 < uname.txt
shachi
chrysalis
kos-mos
@@ -100,7 +100,7 @@ Let's say we want to rewrite that `cut` command above to use pipes. You could
write it like this:
```sh
-cat uname.txt | cut -d' ' -f2
+cat uname.txt | cut -d ' ' -f 2
```
[The mnemonic we use for remembering the `cut` command is that fields are
@@ -110,7 +110,7 @@ separated by the `d`elimiter and you cut out the nth
This will get you the exact same output:
```console
-$ cat uname.txt | cut -d' ' -f2
+$ cat uname.txt | cut -d ' ' -f 2
shachi
chrysalis
kos-mos
@@ -123,7 +123,7 @@ easier to tack on more specific selectors or operations as you go along. For
example, if you wanted to sort them you could pipe the result to `sort`:
```console
-$ cat uname.txt | cut -d' ' -f2 | sort
+$ cat uname.txt | cut -d ' ' -f 2 | sort
chrysalis
kos-mos
ontos
@@ -224,24 +224,52 @@ another. Let's say you have a need for both standard out and standard error to
go to the same file. You can do this with a command like this:
```
+$ rustc foo.rs > foo.log 2>&1
+```
+
+This tells the shell to point standard out to `foo.log`, and then standard
+error to standard out (which is now `foo.log`). There's a footgun here though;
+the order of the redirects matters. Consider the following:
+
+```
$ rustc foo.rs 2>&1 > foo.log
+error: expected one of `!` or `::`, found `main`
+ --> foo.rs:1:5
+ |
+1 | fun main() {}
+ | ^^^^ expected one of `!` or `::`
+
+error: aborting due to previous error
+$ cat foo.log
+$ # foo.log is empty, why???
```
-This tells the shell to point standard error to standard out and then the
-combined output to `foo.log`. There's a short form of this too:
+We wanted to redirect stderr to `foo.log`, but that didn't happen. Why? Well,
+the shell considers our redirects one at a time from left to right. When the
+shell sees `2>&1`, it hasn't considered `> foo.log` yet, so standard out (`1`)
+is still our terminal. It dutifully redirects stderr to the terminal, which is
+where it was already going anyway. Then it sees `1 > foo.log`, so it redirects
+standard out to `foo.log`. That's the end of it though. It doesn't
+retroactively redirect standard error to match the new standard out, so our
+errors get dumped to our terminal instead of the file.
+
+Confusing right? Lucky for us, there's a short form that redirects both at the
+same time, making this mistake impossible:
```
$ rustc foo.rs &> foo.log
```
-[Where can I expect to use that?](conversation://Mara/hmm)
+This will put standard out and standard error to `foo.log` the same way that
+`> foo.log 2>&1` will.
+
+[Will that work in every shell?](conversation://Mara/hmm)
-[It's a bourne shell extension, but I've tested it in `zsh` and `fish`. You can
-also do `&|` to pipe both standard out and standard error at the same time in
-the same way you'd do `2>&1 | whatever`.](conversation://Cadey/enby)
+[It's a bourne shell (`bash`) extension, but I've tested it in `zsh` and `fish`.
+You can also do `&|` to pipe both standard out and standard error at the same
+time in the same way you'd do `2>&1 | whatever`.](conversation://Cadey/enby)
-That will put standard out and standard error to `foo.log` the same way that
-`2>&1 > foo.log` will. You can also use this with `>>`:
+You can also use this with `>>`:
```
$ rustc foo.rs &>> foo.log
@@ -265,9 +293,13 @@ error: aborting due to previous error
[How do I redirect standard in to a file?](conversation://Mara/hmm)
-The answer there is not directly! There is a workaround in the form of a tool
-called `tee` which outputs its standard in to both standard out and a file. For
-example:
+Well, you don't. Standard in is an input, so you can change where it comes
+_from_, not where it goes.
+
+But, maybe you want to make a copy of a program's input and send it somewhere
+else. There is a way to do _that_ using a command called `tee`. `tee` copies
+its standard input to standard output, but it also writes a second copy to a
+file. For example:
```console
$ dmesg | tee dmesg.txt | grep 'msedge'
@@ -345,6 +377,6 @@ What else could you do with pipes and redirection? The cloud's the limit!
---
-Thanks to violet spark for looking over this post and fact-checking as well as
-helping mend some of the brain dump and awkward wording into more polished
-sentences.
+Thanks to violet spark, cadence, and AstroSnail for looking over this post and
+fact-checking as well as helping mend some of the brain dump and awkward
+wording into more polished sentences.