捕获 shell 管道中输出的进程信号“终止”消息

捕获 shell 管道中输出的进程信号“终止”消息

当进程通过信号结束时,会输出一条消息,类似于TerminatedKilled取决于所使用的信号。是否可以捕获该消息?

以这个管道为例:

while true; do timeout 2 sleep 5; done

它没有任何输出,但sleep每 2 秒就会终止一次。添加一个cat

while true; do timeout 2 sleep 5 | cat; done

现在,它Terminated每 2 秒输出一次,但cat看不到它 - 如果我替换cattee somefile,则文件仍为空。

我尝试2>&1在命令行的各个位置进行重定向,但无法将输出Terminated放入文件中。

我认为它们是通过libc链接到终端外壳而不是循环中的命令输出的。

是否有可能将Terminated类似的输出放入管道中?

(最终,我想sleep用 a替换 the ,用脚本替换curlthe ,并处理输出和消息。)catawkcurlTerminated

答案1

分析

是的,这是 shell 打印的Terminated。当timeout 2 sleep 5 | cat你看到Terminated因为cat被终止。和我意思是cat

这在中进行了解释这是我的另一个答案timeout将 SIGTERM 发送到其整个进程组,在您的情况下,该组包括sleep cat

进程组timeout也包括。它似乎没有被它自己的信号杀死,这就是sole不打印shell 的timeout原因。但如果你这样做,那么你将从 shell 中看到,因为 SIGKILL 既不能被捕获也不能被忽略。当使用 SIGKILL杀死时,它也会杀死自己并且 shell 做出反应。timeout 2 sleep 5Terminatedtimeout -s KILL 2 sleep 5Killedtimeoutsleep

所以这才是你所观察到cat的最重要的Terminated。现在,如果您替换sleepcurl, catwith awk,则将timeout终止curlawk。但这并不重要,因为打印消息的是 shell。如果您确实想捕获消息,那么您需要awk在管道中贝壳。


解决方案

如果您确实想捕获消息,那么您需要awk在打印消息的 shell 之后添加一个管道。并且您需要一个被终止的“受害者”进程,没有它就不会有消息。并且您需要一个timeout在 PGID 等于其 PID 的进程组中运行的 shell ,因为这对于该机制至关重要(请参阅链接的答案)。例如,awk在此管道中应成功处理消息:

bash -ic 'timeout 2 sleep 5 | cat' 2>&1 | awk '{print "This is the message: "$0}'

-i很重要;没有它就timeout不会杀死我们可怜的谴责者cat。严格来说,这与交互式或非交互式 Bash 无关。它涉及启用作业控制(在交互式 Bash 中默认启用)或禁用(在非交互式 Bash 中默认启用)。所以这也行得通:

bash -c 'set -m; timeout 2 sleep 5 | cat' 2>&1 | awk '{print "This is the message: "$0}'

更优雅的解决方案

有一种更简单的方法可以做你想做的事。如果最终您想在脚本中运行它,那么您可以利用解释脚本的 shell 不应为命令创建单独的进程组这一事实。在非交互式脚本中timeout … | awk不会杀死awk.

现在您所需要的只是timeout -v告诉您它的作用。以下示例设计为作为非交互式脚本运行。如果您想在交互式 Bash 中测试它,也可以,但必须首先禁用作业控制 ( set +m)。这是脚本:

#/bin/sh
timeout -v 2 sleep 5 2>&1 | awk '{print "This is the message: "$0}'

sleep用。。。来代替curl。您awk应该寻找timeout: sending signal TERM to command '…'而不是尝试检测Terminated

相关内容