sh command: exec 2>&1

Solution 1:

Technically speaking it duplicates, or copies, stderr onto stdout.

Usually you don't need the exec to perform this. A more typical use of exec with file descriptors is to indicate that you want to assign a file to an unused file descriptor, e.g.

exec 35< my_input

BTW Don't forget that the sequence of declaration when piping to a file is important, so

ls > mydirlist 2>&1

will work because it directs both stdout and stderr to the file mydirlist, whereas the command

ls 2>&1 > mydirlist

directs only stdout, and not stderr, to file mydirlist, because stderr was made a copy of stdout before stdout was redirected to mydirlist.

Edit: It's the way that the shell works scanning from left to right. So read the second one as saying "copy stderr onto stdout" before it says "send stdout to mydirlist". Then read the first one as saying "send stdout to the file mydirlist" before it says "duplicate stderr onto that stdout I've set up". I know. It's totally not intuitive!

Solution 2:

One of the better articles I've seen on what "2>&1" does is Bash One-Liners Explained, Part III: All about redirections.

But what the current answers on this question fail to provide is why you'd want to do this after a plain "exec". As the bash man page for the exec command explains: "If command is not specified, any redirections take effect in the current shell".

I wrote a simple script called out-and-err.py that writes a line of output to stdout, and another line to stderr:

#!/usr/bin/python
import sys
sys.stdout.write('this is stdout.\n')
sys.stderr.write('this is stderr.\n')

And then I wrapped that in a shell script called out-and-err.sh with an "exec 2>&1":

#!/bin/bash
exec 2>&1
./out-and-err.py

If I run just the python script, stdout and stderr are separate:

$ ./out-and-err.py 1> out 2> err
$ cat out
this is stdout.
$ cat err
the is stderr.

But if I run the shell script, you can see that the exec takes care of stderr for everything after:

$ ./out-and-err.sh 1> out 2> err
$ cat out
this is stdout.
this is stderr.
$ cat err
$

If your wrapping shell script does a lot more than just the one python command, and you need all output combined into stdout, doing the "exec 2>&1" will make that easy for you.