I've noticed some rather odd behavior when we redirect the output of a shell script that itself redirects some of its output to /dev/stdout or /dev/stderr.
Shell Script
$ cat test.sh
#!/bin/bash -x
echo stdout
echo stderr >&2
echo '/dev/stdout' > /dev/stdout
echo '/dev/stderr' > /dev/stderr
Baseline: No redirection
$ ./test.sh
+ echo stdout
stdout
+ echo stderr
stderr
+ echo /dev/stdout
/dev/stdout
+ echo /dev/stderr
/dev/stderr
If we don't perform any redirection, everything appears as we would expect.
Redirect stdout
$ ./test.sh > out
+ echo stdout
+ echo stderr
stderr
+ echo /dev/stdout
+ echo /dev/stderr
/dev/stderr
$ cat out
/dev/stdout
When we redirect stdout, the "/dev/stdout" line is redirected as expected, but the "stdout" line no longer appears anywhere.
Redirect streams to separate files
$ ./test.sh > out 2> err
$ cat out
/dev/stdout
$ cat err
/dev/stderr
Not only "stderr", but also the "bash -x" lines have vanished.
Redirect streams to the same file
$ ./test.sh > out 2>&1
$ cat out
/dev/stderr
In the final case, we're missing everything we were in the last example, and "/dev/stdout", previously successfully redirected to the file, has also gone missing.
Using exec lines in the shell script to do the redirection, e.g. exec 1>out; exec 2>&1;
, yields the same behavior as if we redirect from the command line.
The question: Why are the missing lines missing, and what happens at each line of the script (including the implicit exec lines being executed by the command line redirection) so as to cause this to happen? Preferably the answer to the latter will describe the system calls involved (dup2?).