Search code examples
stdoutswapstderrio-redirection

Why is the instruction to swap stderr with stdout backward?


In numerouse places, I've found people suggesting that you can swap stderr with stdout as follows:

command 3>&2 2>&1 1>&3

This looks backwards to me. If we send 3 to 2 and then immediately send 2 to 1 (which now would appear to be sending both 3 and 2 to 1). I think there's something basic I don't understand about IO redirection, but I can't find anything which clarifies it.


Solution

  • You will find a detailed explanation at http://www.catonmat.net/blog/bash-one-liners-explained-part-three/ , section 21:

    $ command 3>&1 1>&2 2>&3 Here we first duplicate file descriptor 3 to be a copy of stdout. Then we duplicate stdout to be a copy of stderr, and finally we duplicate stderr to be a copy of file descriptor 3, which is stdout. As a result we've swapped stdout and stderr.

    There is more detail, and pictures, at the link given. The key insight is:

    3>&1 means "3 points to where 1 is pointing". Then 1>&2 says "now 1 points to where 2 is pointing" (1 now points to stream 2, but 3 doesn't follow...), and finally 2>&3 says "now 2 points to where 3 is pointing (which is stream 1).

    Graphically (but see link - it's much better than my ascii-art):

    0 --> /dev/tty0
    1 --> /dev/tty1
    2 --> /dev/tty2
    

    After 3>&1:

    0 --> /dev/tty0
    1 --> /dev/tty1
    2 --> /dev/tty2
    3 --> /dev/tty1
    

    After 1>&2:

    0 --> /dev/tty0
    1 --> /dev/tty2
    2 --> /dev/tty2
    3 --> /dev/tty1
    

    After 2>&3:

    0 --> /dev/tty0
    1 --> /dev/tty2
    2 --> /dev/tty1
    3 --> /dev/tty1
    

    As you can see, 1 and 2 have been swapped. The same link recommends closing temporary stream 3 with 3>&-