3

Possible Duplicate:
Order of redirections

Apart from the standalone exec >&2 to redirect the current shell's input and output are there any behavioral differences in the following commands:

  1. echo -en "C\nB\nA\n" | sort 2>/dev/stdout >&2
  2. echo -en "C\nB\nA\n" 2>/dev/stdout >&2 | sort
  3. 2>/dev/stdout >&2 echo -en "C\nB\nA\n" | sort

If the above commands were equivalent which is the preferred variant?

Tim Friske
  • 2,260
  • 1
    None of those is idiomatic. They all contain redundancies. How did you come up with those? Are they homework? – Mikel Nov 19 '12 at 04:49
  • 1
    I find your comment quite harsh. The above commands purely serve as illustrative examples. I'm also very well aware that the net effect of 2>/dev/stdout >&2 is zero. The question is primarily concerned with "where to place" and only secondarily with "what does" the redirection. – Tim Friske Nov 19 '12 at 09:18
  • @TimFriske The net effect of 2>/dev/stdout >&2 is most definitely not zero. – Chris Down Nov 19 '12 at 11:46
  • @ChrisDown I meant that the output sent to > is still /dev/stdout after 2>/dev/stdout >&2. The redirection itself definetly has its side effects. – Tim Friske Nov 19 '12 at 13:48
  • "Where to place" depends on what you want it to do. And I can't figure that out from your question. You seem to fundamentally misunderstand >&2. Please read the man page first, then ask a clear question. – Mikel Nov 19 '12 at 15:14
  • @Mikel No, that earlier question deals with switching the >&2 and the 2>foo but not with the placement of the redirection within a simple command or a pipeline. – Gilles 'SO- stop being evil' Nov 19 '12 at 23:09
  • 2
    Right. There's at least two, if not three issues this question touches on, without ever clearly identifying what the actual question is. The linked question helps understand that 2>/dev/stdout >&2 contains redundancies. The question needs to have these redundancies removed, and then be recast in the form of a clear question. If it was only about redirections in pipelines, it would indeed be useful. – Mikel Nov 19 '12 at 23:42

2 Answers2

5

First, in a simple command (basically, the name of a program followed by some arguments), the relative position of arguments and redirections doesn't matter. You can even have redirections before the command name. The following are all equivalent:

foo --bar qux >out 2>err
foo >out --bar 2>err
>out 2>err foo --bar qux

(I won't list all the possibilities.) It's usual to put the redirections at the end, so you might surprise a future reader if you don't do that. However, it's only a matter of style. There is some benefit to putting input redirections before the command and output redirections afterward, particularly in pipelines, because it keeps the reading order identical to the processing order:

<input.txt command1 | command2 | command3 >output.txt

(contrast command1 <input.txt | command2 …, which puts the origin after the first processing step.)

In compound commands, you do need to put the redirections at the end; for example, in the following snippets, you can't put the redirection anywhere else:

while some_predicate; do some_action; done <in >out
{ command1; command2; } <in >out

When there are multiple redirections, the order is important if they overlap, i.e. if they have file descriptors in common. See Order of redirections

In a pipeline, redirections apply to each piped command. In your examples, the redirections apply to (1) the sort command only, (2,3) the echo command only. As explained above, (2) and (3) are equivalent.

In (2) and (3), the output from echo ends up at the same place it was before the redirection. If you'd written echo -en "C\nB\nA\n" >&2 | sort, there would be no output to stdout from the command on the left-hand side of the pipe, so sort would see an empty stdin.

You can redirect the input or output of a block of commands by putting them in braces:

{ command1 | command2; } 2>error.log

I assume your choice of redirections was for demonstration purposes only — 2>/dev/stdout >&2 is a complex way of writing 2>&1 (redirect standard error (i.e. fd 2) to wherever standard output (i.e. fd 1) currently goes).

2

1 is different than 2 and 3. 2 and 3 are identical.

In version 1, C\nB\nA\n is sent to sort. sort's FD 2 is mapped from its original destination (STDERR) to STDOUT and then FD 1, which would have gone to STDOUT anyway, is sent to... sort's STDOUT again (rather pointlessly).

In versions 2 and 3, echo's FD 2 is mapped from its original destination (STDERR) to STDOUT and then FD 1, which would have gone to STDOUT anyway, is sent to echo's STDOUT.

Functionally these commands will only produce different output if one of the commands sends something to STDERR.

In version 1, if echo outputs something to FD 2, it will go to STDERR, but in 2 and 3, it will go to STDOUT (and thus also be piped to sort). Also, in version 1, if sort sends something to FD 2, it will go to STDOUT, whereas in versions 2 and 3, that output will go to STDERR.

In terms of the "preferred variant", you should really be using something more like this (assuming you want echo's STDERR to go to sort):

echo -en "C\nB\nA\n" 2>&1 | sort

This works because FD 1 already goes to STDOUT by default, just have FD 2 copy the file description to its descriptor.

Chris Down
  • 125,559
  • 25
  • 270
  • 266