为什么后台作业会带有`| less` 被停止,而另一个没有它的正在运行?

为什么后台作业会带有`| less` 被停止,而另一个没有它的正在运行?
$ pdfgrep -R -i spark . | less &
$ pdfgrep -R -i spark . &

$ jobs
[3]-  Stopped                 pdfgrep -R -i spark . | less
[4]   Running                 pdfgrep -R -i spark . &
  1. 为什么有的那个会| less停止,而没有的那个却在运行?

    停止的后台作业不会从标准输入读取。所以不可能是这个原因。

  2. 我将作业设置为后台的原因是我可以在同一个终端会话中执行其他操作。

    我使用管道的原因less是因为我不希望在做其他事情时输出到标准输出会弄乱终端会话的屏幕。

    有什么办法可以实现上述两个目标吗?与将输出保存到文件相比,我稍微更喜欢不将输出保存到文件,因为记住文件、读取和删除它们需要更多的时间。

谢谢。

答案1

让我们更仔细地看看发生了什么less

$ pdfgrep -R -i spark . | strace less &
[...]
open("/dev/tty", O_RDONLY|O_LARGEFILE)  = 3
ioctl(3, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig -icanon -echo ...}) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGTTOU {si_signo=SIGTTOU, si_code=SI_KERNEL} ---
--- stopped by SIGTTOU ---

作业控制限制后台作业中的进程在控制终端上执行某些操作。

  • 如果后台进程尝试从终端读取数据,则会向其发送一个SIGTTIN信号,该信号通常会停止(暂停)该进程。

  • 如果后台进程尝试设置终端的参数,则会向其发送一个SIGTTOU信号,该信号通常也会停止该进程。这就是这里发生的事情TCSETSW 读写控制。该less程序在启动后立即尝试将终端置于原始模式,甚至在它知道是否有任何内容可显示之前。

    这样做有一个很好的理由:您不希望后台作业异步更改您的终端,例如,原始模式打开而回显关闭。 (后台进程可以得到使用 ioctl 的终端参数TCGETS而不停止 - 请参阅上面的列表。)

  • 如果后台进程尝试写入终端并且终端设置了标志tostop,则会向其发送SIGTTOU信号。

您可能没有tostop设置标志(运行stty -a来检查)。如果不这样做,这样的后台命令pdfgrep -R -i spark . &不会更改任何终端设置,只要它尝试,就能够写入您的终端。

您还写道:

我使用 less 的原因是因为我不希望在做其他事情时输出到 stdout 会弄乱终端会话的屏幕

less 程序最终会将输出发送到终端,一次一屏。如果您运行stty tostopbeforepdfgrep | less &或 before pdfgrep &,那么它们仅在位于前台时才会输出到您的终端。

答案2

回答你的第二个问题:我使用 screen(1) 通过一个类似 tty 的设备复用许多命令。

至少有一个选择、 tmux(1) 以及两者的简化包装器 byobu(1)。

答案3

less正在尝试与 TTY 交互(输出到),但由于它作为后台作业运行,因此没有可写入的 TTY。pdfgrep另一方面,该实用程序写入标准输出。

在我的系统上,我得到了更具描述性的输出

$ cat ~/.profile | less &
[1] 51758 67354
$
[1] + Done                 cat ~/.profile |
      Stopped (tty output) less

在这个简单的示例中,cat完成发送 my .profileto less,但less无法显示它,因为它是后台作业。因此就有了这条Stopped (tty output) less消息。

但该less过程仍在运行。这只是暂时地停了下来。要切换到它,请使用fg %1(该数字对应于“已停止”消息中方括号中报告的作业编号,并且在启动作业时也应该已报告)。


有关的:Linux 中的 top、top&、top & 命令

相关内容