Bash 文件重定向错误?

Bash 文件重定向错误?

据我对程序 IO 的了解,有stdinstdoutstderr数据流(以及返回代码)。stdoutstderr是两个数据输出流。因此,如果我使用 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

我不明白这里到底发生了什么事。

截图证明:

Bash 重定向错误

答案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

相关内容