What will this command do?
exec 2>&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!
It ties standard error to standard out
the 2 is stderr and 1 is stdout. When you run a program, you'll get the normal output in stdout, but any errors or warnings usually go to stderr. If you want to pipe all output to a file for example, it's useful to first combine stderr with stdout with 2>&1.
Like @cma said, it puts stderr on stdout. The reason you might want this behavior is to use grep or any other utility to capture output that only appears on stderr. Or you might just want to save all the output, including stderr, to a file for later processing.
These day I was suck at this problem too, but now I'm jump out from it.
So, please allow me to explain what happen after you input exec 1>&2 in CLI.
I want to destruct the problem piece by piece, so if you know the knowledge alread just skim it to save your time.
exec stands for:exec is a built-in command in Linux. Different from the tradition command which just fork a sub shell process, exec could change current shell process.
What is I/O redirection:
Redirection is a feature in Linux. With this you can change the standard input/output devices. In Linux, there are three file descriptors by default.
Handle Name Description
0 stdin Standard input
1 stdout Standard output
2 stderr Standard error
Let me see an example:
$ pstree -p | grep 'term' | tr -d ' '$ sudo ls -l /proc/{pid}/fd
bash
$ pstree -p | grep -i 'terminal' | tr -d ' '
||||-gnome-terminal-(6008)-+-bash(7641)-+-grep(8355)
$ sudo ls -l /proc/7641/fd
total 0
lrwx------ 1 alopex alopex 64 Oct 27 19:39 0 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 1 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 2 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 255 -> /dev/pts/3
As you can see, the ls list the PID(6860) process file. First they all name by number(0, 1, 2), second they all link file link to /dev/pts/3, it means whatever standard input/output/error all will show up in pts3.bash
$ ls /tmp/stdout
ls: cannot access '/tmp/stdout': No such file or directory
$ exec 1>/tmp/stdout
$ ls
$ pwd
$ echo "Are you ok"
$
The command output was disappear at that time.bash
$ sudo ls -l /proc/7641/fd
total 0
lrwx------ 1 alopex alopex 64 Oct 27 19:39 0 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 1 -> /tmp/stdout
lrwx------ 1 alopex alopex 64 Oct 27 19:39 2 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 255 -> /dev/pts/3
Obviously, we can notice that the 1(file descriptor) already change link to /tmp/stdout. As us except, the standard output transfer to /tmp/stdoutbash
$ exec 1>&2
$ cat /tmp/stdout
a.sh
/home/alopex
Are you ok
$ sudo ls -l /proc/7641/fd
total 0
lrwx------ 1 alopex alopex 64 Oct 27 19:39 0 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 1 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 2 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 255 -> /dev/pts/3
Again, the 1(file descriptor) link to the /dev/pts/3, we can see the output again.Summary:
exec 1>&2 make the standard output ---> standard errorAn practical example, when to use exec 2>&1: The following example is a test case executing 1000 HTTP requests and measuring the time. The output of the test case should be send to a log file, but the measured time should be send to standard output.
In order to achieve this standard output gets duplicated by: exec 3>&1. Then standard output gets redirected to the file log: exec 1>log. And finally standard error gets redirected to standard output: exec 2>&1. This means standard error will also be send to the file log, because standard output has already been redirected. After this file descriptor 3 can still be used to send messages to standard output of the script, although everything else goes into the log file: printf ... >&3.
#! /bin/bash
export LC_ALL=C
exec 3>&1
exec 1>log
exec 2>&1
set -eux
timestamp () { date +%s.%N; }
loops=${1:-1000}
t0=$(timestamp)
for n in $(seq "$loops")
do
curl --silent --show-error --noproxy \* http://localhost:8000 &
done
wait
t1=$(timestamp)
printf '%d loops: %0.4f seconds\n' "$loops" "$(bc <<< "$t1 - $t0")" >&3