管道意外停止

管道意外停止

我正在运行一个脚本,它本身运行良好,但通过 less(或其他抓取 tty 的程序)管道传输时会停止。我将其归结为以下代码片段:

$ env -i TERM=vt100 bash --norc --noprofile

bash-3.2$ echo `uname;date` | less -EX

[2]+  Stopped                 echo `uname;date` | less -EX
bash-3.2$ fg
echo `uname;date` | less -EX
Darwin Mon Dec 12 13:44:02 PST 2022

同样的命令在 Linux 上运行没有问题。如果我把它放到子 shell 中,它也能很好地运行:

bash-3.2$ (echo `uname;date;`) | less -EX
Darwin Mon Dec 12 13:46:34 PST 2022

我可以在实际程序中使用子 shell 作为解决方法,但这很奇怪。有什么建议吗?

系统信息:

bash-3.2$ uname -rms
Darwin 21.6.0 x86_64

编辑:我在上面使用了反引号,但使用新式美元括号替换(您应该始终这样做,我只是快速书写)在这里没有什么区别。

bash-3.2$ echo $(uname -rms;date;) | less -EX

[1]+  Stopped                 echo $(uname -rms;date;) | less -EX
bash-3.2$ fg
echo $(uname -rms;date;) | less -EX
Darwin 21.6.0 x86_64 Mon Dec 12 14:43:47 PST 2022
bash-3.2$ 

编辑:被指向这个帖子指出不仅仅是读取和写入 tty 可以生成 SIGTTOU,它还在其上运行 ioctl(也许是像isatty()在 stdio 中一样看似无害的东西来确定默认缓冲模式?),这最终是一种竞争条件,额外的进程/替换增加了足够的时间来命中或错过竞争。

考虑到这一点,我尝试了另一种复制方法:

$ for x in $(seq 100); do echo $(true && uname) | less -EX ; done

这通常会在我的 MacBook 上产生 1-3 个停止的作业,可能取决于它的加载程度。

在命令上添加子 shell 似乎会使其更加可靠,但代价是使其速度变慢,但是竞争条件可能仍然存在。

相关内容