Why is 1>a.txt 2>&1 different from 1>a.txt 2>a.txt ? (Example shown)

With 1>a.txt 2>&1, file descriptor #1 is duplicated to #2. They both reference the same "open file", and they both share the current position and r/w mode. (There's actually no difference at all between using 2>&1 and 2<&1.)

With 1>a.txt 2>a.txt, both file descriptors are opened independently and have separate cursor positions. (The file gets truncated twice too.) If you write "Hello" to fd #1, its position is advanced to byte 5, but fd #2 remains at byte 0. Printing to fd #2 will just overwrite the data starting from 0.

This is easy to see if the second write is shorter:

$ perl -e 'STDOUT->print("abcdefg\n"); STDOUT->flush; STDERR->print("123");' >a.txt 2>a.txt

$ cat a.txt 
123defg

Note that Perl has internal buffering, so in this example an explicit flush() is necessary to ensure that fd #1 data is written before fd #2 data. Otherwise, the streams would be flushed in unpredictable order on exit.

For comparison, if the file descriptors are shared, the writes just follow each other:

$ perl -e 'STDOUT->print("abcdefg\n"); STDOUT->flush; STDERR->print("123");' >a.txt 2>&1

$ cat a.txt 
abcdefg
123

Tags:

Shell