1

I am trying to echo outputs to stderr and redirect stderr to a file at the same time, I noticed that the order of redirection matters, but I don't understand why it has to be this way.

The file asap is empty using either of the following commands:

echo "Fatal error." >&2 2>asap
echo >&2 "Fatal error." 2>asap

But this works, logging "Fatal error" to the file asap.

echo "Fatal error." 2>asap >&2

Why?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
once
  • 1,369
  • 4
  • 22
  • 32
  • See [How to pipe stderr and not stdout](https://stackoverflow.com/questions/2342826/how-to-pipe-stderr-and-not-stdout/) for most of the required information. Note the 'au contraire' comment, in particular. – Jonathan Leffler Nov 10 '19 at 03:58
  • Note that the redirections can be positioned anywhere on the command line relative to the command name and arguments. That is: `xml some -command` is the same as `some -command xml` and so on. So, there is no difference between the first two commands. – Jonathan Leffler Nov 10 '19 at 04:00
  • [Cross-site duplicate](https://unix.stackexchange.com/questions/37660/order-of-redirections) – that other guy Nov 10 '19 at 04:02

2 Answers2

2

See How to pipe stderr and not stdout for most of the required information. Note the 'au contraire' comment, in particular. Remember that all redirections are completed before the command is executed, and that the redirections are processed from left to right. (Pipelines marginally complicate the story. Most of the time, the pipe redirection of standard output is done before any other redirection. The exception is a Bash-specific syntax, |&. Go read the Bash manual for the details — and then don't use |&.)

Note that the redirections can be positioned anywhere on the command line relative to the command name and arguments. That is:

<html> xml some -command

is the same as

some -command <html >xml

and so on. So, there is no difference between the first two commands in the question. (And I think you found that out for yourself.)

The first command in the question:

echo "Fatal error." >&2 2>asap

first redirects standard output to the current standard error, then redirects standard error to the file (leaving standard output pointing to the original standard error), and then executes the echo command. The message goes to the original standard error (your terminal), and not to the file because echo doesn't write to standard error.

The last command:

echo "Fatal error." 2>asap >&2

first sends standard error to the file, then sends standard output to the same place that standard error is going to (the file), and then executes the echo command. Since standard output is going to the file, there's nothing seen on the terminal.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    'all redirections are completed before the command is executed', it all makes sense now. – once Nov 10 '19 at 04:16
  • Just out of interest, why do you suggest not using `|&`. It's invaluable to shorten things where you *want* to coalesce output and error, such as shortening `gcc blah blah 2>&1 | less`. – paxdiablo Nov 10 '19 at 06:10
  • Because it behaves differently from any other redirection — _If ‘|&’ is used, command1’s standard error, in addition to its standard output, is connected to command2’s standard input through the pipe; it is shorthand for `2>&1 |`. This implicit redirection of the standard error to the standard output is performed after any redirections specified by the command._ The 'is performed after' part means it is not the same as `2>&1 |` — you can get surprises (mostly if you're doing weird stuff with redirections). I don't find the contraction useful — it isn't that much shorter. YMMV — that's fine. – Jonathan Leffler Nov 10 '19 at 06:14
2

Redirections happen left to right so they can act differently depending on placement.

For example, the two commands:

runme >somefile 2>&1
runme 2>&1 >somefile

have different effects because of the order.

The first points standard output to the file somefile, then standard error to that new standard output (the file).

The second points standard error to the current standard output (the terminal, most likely) then points standard output to the file.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953