Consider this Bash function:
func() {
( echo STDOUT; echo STDERR >&2 ) 1>$1 2>$2
}
And then this:
$ func /dev/stdout /dev/stdout | wc -l
2
$ func /dev/stdout /dev/stderr | wc -l
STDERR
1
Those are expected.
Then this:
$ func /dev/stderr /dev/stdout | wc -l
STDOUT
STDERR
0
I would expect
STDOUT
1
here: STDOUT
written to stderr (not seen by wc
), and STDERR
written to stdout (seen by wc
).
Another one:
$ func /dev/null /dev/stdout | wc -l
0
I'd expect STDERR
to be written to stdout, therefore seen by wc
.
what's happening here?
How to achieve what I want?
After it performs the redirection 1>/dev/stderr
, stdout
is equivalent to stderr
. Then when it does 2>/dev/stdout
, /dev/stdout
means the original stderr, so it's redirecting stderr to where was already going. Both FD's are writing to the same place.
If you want to swap stdout and stderr, you need to save one of the original streams somewhere before redirecting it.
some_cmd 3>&1 1>&2 2>&3 3>&-
This saves stdout on fd 3, copies stderr to stdout, copies fd 3 (the original stdout) to stderr, and then closes the temporary fd 3.
You can use 3>&1
and /dev/fd/3
when calling the function to achieve your result:
$ func /dev/stderr /dev/fd/3 3>&1 | wc -l
STDOUT
1