我正在运行一个脚本,它本身运行良好,但通过 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 似乎会使其更加可靠,但代价是使其速度变慢,但是竞争条件可能仍然存在。