Note that the order of redirections
is significant. For example, the
command
ls > dirlist 2>&1
directs both standard output and
standard error to the file dirlist,
while the command
ls 2>&1 > dirlist
directs only the standard output to
file dirlist, because the standard
error was duplicated from the
standard output before the standard
output was redirected to dirlist.
Does it look a little arcane, yes, esp. until one memorizes it.Can it be memorized? Yes, because it is just a single 'incantation': "2>&1". Just put that redirection operator before the redirection of the standard output to the file, and the result is stdout goes to the file, stderr goes to the pipe.
Note that the order of redirections is significant. For example, the command
ls > dirlist 2>&1
directs both standard output (file descriptor 1) and standard error (file descriptor 2) to the file dirlist, while the command
ls 2>&1 > dirlist
directs only the standard output to file dirlist, because the standard error was made a copy of the standard output before the standard output was redirected to dirlist.
[0]: https://www.gnu.org/software/bash/manual/html_node/Redirecti..."Redirecting streams" winds up being confusing - it's all just `dup2`.
Yes, I know that underneath it's all calls to `pipe()` and `dup2()`, which I can do (and have done) in a language other than shell. It's the shell redirection syntax (for anything more complex than simple redirection or a pipe) that just doesn't make sense to me.
command 2>&1 > >(cat - | cat - > fd1) | cat - | cat - > fd2
Note, the extra 'cats' are just to show a "string of commands".How to read this:
When Bash sets up the file descriptors for 'command' it initially makes descriptor 1 refer to the pipe, and descriptor 2 refer to the terminal.
So, the dup operator (2>&1) copies the fd in descriptor 1 (which is the pipe) into descriptor 2 (so after the dup operator is processed both stderr and stdout for command reference the pipe).
Next descriptor 1 is replaced (the > operator) by a reference to a fifo created by the process substitution operator (the >(...) operator).
So now command's descriptor 1 refers to the fifo created by >() (which itself contains a "string of commands").
Then, because stderr for command was made to be a copy of what was previously stdout (before modifying stdout) it continues to refer to the pipe Bash setup (the | operator), and stderr now flows out over the pipes to another "string of commands".
( echo "stdout"; echo "stderr" 1>&2 ) 2>&1 1>/dev/null
I mean, I would expect the syntax to be something like:
but no ... it's some incomprehensible mess of redirection arcana to get that to work.