据我对程序 IO 的了解,有stdin
、stdout
和stderr
数据流(以及返回代码)。stdout
和stderr
是两个数据输出流。因此,如果我使用 bash 重定向关闭其中一个输出流,我就可以缩小文本要发送到哪个流的范围。对吗?
我正在运行 Ubuntu 18.04.1 LTS,并且遇到了这个与 bash 重定向相关的奇怪问题。
让我解释一下这个例子。这是我的命令:
# apt-cache show php5
N: Can't select versions from package 'php5' as it is purely virtual
N: No packages found
# |
该php5
软件包在 Ubuntu 18.04 上不存在,因此apt-cache
显示错误。我假设此文本已发送到stderr
流,因此我尝试关闭该流:
# apt-cache show php5 2>&-
# |
看来这验证了文本已通过 发送stderr
。到目前为止一切顺利!但现在作为健全性检查,我尝试关闭stdout
(我现在应该可以看到错误文本):
# apt-cache show php5 1>&-
# |
什么!?stdout
这次我重定向了,但stderr
还是没有显示?
根据互联网,我的文件描述符是正确的:https://www.gnu.org/software/bash/manual/html_node/Redirections.html
我不明白这里到底发生了什么事。
截图证明:
答案1
总结:不是的bash
,这是apt-cache
在弄乱文件描述符。
apt-cache
正在做一些非常有趣的事情——它倾向于不是写出以N:
标准输出字符开头的行。
考虑一下:
$ apt-cache show nonexistent
N: Unable to locate package nonexistent
E: No packages found
我们看到两行,一行以 开头,N:
另一行以 开头E:
。N:
行输出到标准输出。在您的示例中,有两N:
行。
# apt-cache show php5
N: Can't select versions from package 'php5' as it is purely virtual
N: No packages found
如果您通过以下方式跟踪系统调用,strace -e write -f bash -c 'apt-cache show randomtext >&-'
您会看到写入E:
行的情况,但是N
没有行:
[pid 12450] write(2, "E", 1E) = 1
[pid 12450] write(2, ": ", 2: ) = 2
[pid 12450] write(2, "No packages found", 17No packages found) = 17
[pid 12450] write(2, "\n", 1
) = 1
[pid 12450] +++ exited with 100 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12450, si_uid=1000, si_status=100, si_utime=5, si_stime=2} ---
+++ exited with 100 +++
因此,apt-cache
它足够智能,可以检查重定向的标准输出。但是呢stderr
?显然写入仍然存在:如果你这样做,
strace -e write,openat,dup2 -f bash -c 'apt-cache show randomtext 2>&-
你会看到apt-cache
打开/dev/null
时仍然有一些东西存在stderr
:
[pid 12543] openat(AT_FDCWD, "/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 2
....
[pid 12543] write(2, "N", 1) = 1
[pid 12543] write(2, ": ", 2) = 2
[pid 12543] write(2, "Unable to locate package randomt"..., 35) = 35
[pid 12543] write(2, "\n", 1) = 1
[pid 12543] write(2, "E", 1) = 1
[pid 12543] write(2, ": ", 2) = 2
[pid 12543] write(2, "No packages found", 17) = 17
[pid 12543] write(2, "\n", 1) = 1
[pid 12543] +++ exited with 100 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12543, si_uid=1000, si_status=100, si_utime=5, si_stime=3} ---
+++ exited with 100 +++
如果你对 bash 中的其他程序执行相同操作,它将按预期工作:
# stdout closed, stderr not
$ ls -l /proc/self/fd >&-
ls: write error: Bad file descriptor
# stdout open , stderr closed, and it's number is assigned to whatever command is trying to open - in this case /proc/self/fd directory
$ ls -l /proc/self/fd 2>&-
total 0
lrwx------ 1 xie xie 64 Oct 6 11:32 0 -> /dev/pts/1
lrwx------ 1 xie xie 64 Oct 6 11:32 1 -> /dev/pts/1
lr-x------ 1 xie xie 64 Oct 6 11:32 2 -> /proc/12723/fd