当“输出”进程退出时终止匿名管道

当“输出”进程退出时终止匿名管道

假设我在 shell 脚本中有类似的东西

command1 | command2

现在我怎样才能让它在退出command2时终止command1

编辑:

command2当尝试从标准输入读取并注意到它返回 0 时,默认情况下通常会发生这种情况。您有一些具体的示例吗?

干得好:echo test | xmobar

xmobar我想这也可以用作替代品

#!/bin/sh
while :; do :; done

答案1

这条评论解释当管道的另一端关闭时程序如何终止(或不终止):

关闭管道根本command1不会说明command2任何问题。在command2读取管道、清空它并获得 EOF之前不会发生任何事情。即使如此,如果仍有工作要做,它也不必退出。类似地,如果command2先退出,command1则在写入管道之前不会发现它,此时它会收到SIGPIPE.如果它捕获了这一点,它也可以继续进行其他工作。

所以这就是可以自动发生的事情。现在你的问题是:

command1 | command2

我怎样才能使它在退出command2时终止command1[即使command2没有注意到或不想终止]?

如果您的 shell 在单独的进程组中运行管道,请尝试终止整个组。例如,当启用作业控制时,Bash 会执行此操作 ( set -m)。默认情况下,它对于交互式 shell(在支持它的系统上)启用,但在脚本中不启用。

示例代码:

#!/bin/bash
set -m
( command1; kill -s INT 0 ) | command2

整个管道在一个单独的进程组中运行,其 PGID(进程组 ID)等于第一部分的 PID,在本例中是一个子 shell。kill 0向其自己的进程组发送信号。这样我们就command2command1终止后发出信号。

笔记:

  • 在 Bash 中kill是内置的,因此kill在示例中不是分配了 PID 和 PGID 的单独进程。因此上面这句话“自己的进程组”并不严格,应该是“子shell的进程组”。它仍然是我们想要使用的确切进程组。内置kill的或/bin/kill可以使用的,任何一个都可以。
  • command2可能会改变自己的进程组。如果是这样,该解决方案将不起作用。
  • 因为几乎所有信号都command2可能忽略该信号或以几乎任何方式处理它。选择适合您需求的信号。
  • kill终止后立即调用command1可能为时过早。它可能会导致在读取和处理;command2生成的所有数据之前退出。command1您可能希望它处理所有数据。根据command2行为方式,延迟可能会有用kill(例如sleep 2; kill …)。请注意,(通用)Linux 不是实时操作系统,因此,如果情况足够糟糕,任何固定的延迟都可能会变得太短。

相关内容