From what I understand about program IO, there are stdin
, stdout
, and stderr
data streams (and a return code). stdout
and stderr
are the two data output streams. So if I use bash redirection to close one of the output streams, I can narrow down which stream that text is being sent to. Right?
I'm running Ubuntu 18.04.1 LTS and I'm running into this bizarre issue with bash redirection.
Let me explain the example. Here is my command:
# apt-cache show php5
N: Can't select versions from package 'php5' as it is purely virtual
N: No packages found
# |
The php5
package does not exist on Ubuntu 18.04 so apt-cache
displays an error. I would assume this text is sent to the stderr
stream, so I attempted to close that stream:
# apt-cache show php5 2>&-
# |
It appears this verifies that the text was sent through stderr
. All good so far! But now as a sanity check, I tried closing stdout
(I should see the error text now):
# apt-cache show php5 1>&-
# |
What!? I redirected stdout
this time but stderr
is also not showing up?
According to the internet, I have my file descriptors correct: https://www.gnu.org/software/bash/manual/html_node/Redirections.html
I can't figure out what could be going on here.
Screenshot proof:
TL;DR: It's not
bash
, it'sapt-cache
that's messing around with file descriptors.apt-cache
is doing something very interesting - it tends to not write out lines starting withN:
characters intended for stdout.Consider this:
We see two lines, one starting with
N:
one starting withE:
.N:
lines go to stdout. In your example, you have twoN:
lines.If you trace the system calls via
strace -e write -f bash -c 'apt-cache show randomtext >&-'
you'll see that writingE:
lines happens, butN
lines aren't there:So
apt-cache
is smart enough to check for redirected stdout. But what aboutstderr
? Apparently writes are still there: if you dostrace -e write,openat,dup2 -f bash -c 'apt-cache show randomtext 2>&-
you'll see thatapt-cache
opens/dev/null
to still have something present forstderr
:If you perform the same with other programs in bash, it works as expected: