将 stderr 全局重定向到 /dev/null 后的不可见提示

Sam*_*Sam 3 bash debian io-redirection

学习TLDP 的高级 Bash 脚本指南我无法在 debian 9 的 bash 4.4.12 中重建以下 shell 输出,包括 tty 和 pts:

bash$ lsof -a -p $$ -d0,1,2
COMMAND PID     USER   FD   TYPE DEVICE SIZE NODE NAME
 bash    363 bozo        0u   CHR  136,1         3 /dev/pts/1
 bash    363 bozo        1u   CHR  136,1         3 /dev/pts/1
 bash    363 bozo        2u   CHR  136,1         3 /dev/pts/1


bash$ exec 2> /dev/null
bash$ lsof -a -p $$ -d0,1,2
COMMAND PID     USER   FD   TYPE DEVICE SIZE NODE NAME
 bash    371 bozo        0u   CHR  136,1         3 /dev/pts/1
 bash    371 bozo        1u   CHR  136,1         3 /dev/pts/1
 bash    371 bozo        2w   CHR    1,3       120 /dev/null
Run Code Online (Sandbox Code Playgroud)

每当我运行第二个命令时,shell 提示符就会消失,所有键盘输入都停止显示,但我仍然可以运行命令并查看它们的输出。这是为什么?

Jde*_*eBP 9

这是因为您重定向了 shell 的标准错误。

根据标准,这就是符合 POSIX 的 shell 应该编写其交互式提示的地方。

  • The Bourne AgainHeirloom Bourne、(DebianFreeBSD93 KornMirBSD Korn、(FreeBSD、OpenBSD 和Debian)PD Korn、(FreeBSDDebian)Almquist 和Watanabe shell 都符合这方面的要求,并将它们的交互提示写到标准错误。您会看到所有这些都缺乏及时的行为。

    然而,不回显输入行为要复杂得多:

    • Debian PD Korn、Debian Almquist 和 Heirloom Bourne shell 没有实现自己的行编辑器,而是依赖于内核中的终端行规则提供的行编辑器。您仍然会看到回显您键入的内容作为他们的标准输入。
    • Watanabe、(FreeBSD 93) Korn 和 (Debian 93) Korn shell 实现了它们自己的行编辑器,当它们(重新)显示正在编辑的输入行时,它们也会写入标准错误。然而,他们把终端回波执行前exec命令,以及(因为标准误差不再是终端装置)不能再次关闭它调用用于他们的下一个输入的行编辑器时。因此,您将看到终端线路规则回显了您键入的进一步输入,即使来自 shell 行编辑器的输入回显将转到现在重定向的标准错误。他们的行编辑器也会以微妙的方式出错,例如无法识别任何进一步的终端大小变化。
    • MirBSD Korn、(FreeBSD PD) Korn 和 (OpenBSD PD) Korn shell 实现了它们自己的行编辑器,它们(重新)将编辑过的行显示为标准错误,但/dev/tty直接打开另一个文件描述符以控制诸如终端回显之类的东西. 在为下一个输入调用行编辑器时,他们成功地再次关闭回声。因此,您将不会看到您键入的进一步输入由他们的行编辑器终端行规则回显。
    • Bourne Again 和 FreeBSD Almquist shell 实现了他们自己的行编辑器,将编辑过的行(重新)显示为标准错误,但使用标准输入来控制终端回显等内容。在为下一个输入调用行编辑器时,他们成功地再次关闭回声。因此,您将不会看到您键入的进一步输入由他们的行编辑器终端行规则回显。
  • BusyBox的Almquistž弹不符合POSIX在这方面。他们都实现了自己的行编辑器。有了这两者,你就会看到附录让你相信会发生的行为。

    • BusyBox Almquist shell 的行编辑器使用标准输出作为输入回显,这也是它编写提示的地方。它完全不受标准错误重定向的影响。但是您可以通过重定向标准输出来获得效果。它使用标准输入来识别终端大小的变化。
    • Z shell 努力寻找终端设备来运行 ZLE,直到并包括显式打开/dev/tty. 它在启动时将文件描述符复制到终端设备,然后 ZLE 将其用于所有内容;用于回显键入的输入、读取键入的输入、编写交互式提示以及打开和关闭终端回显。因此,ZLE 不受标准错误、输出甚至输入的后续重定向的影响。如果您愿意,您可以将所有三个重定向到/dev/nullby exec,Z shell 仍会以交互方式提示您输入并接收输入。

Thompson shell 首先不支持 shellexec命令机制,因为它早于它的发明。)

你应该向作者 Stéphane Chazelas 抱怨那个附录是错误的,这样它可能会得到修复。

进一步阅读