当进程通过信号结束时,会输出一条消息,类似于Terminated
或Killed
取决于所使用的信号。是否可以捕获该消息?
以这个管道为例:
while true; do timeout 2 sleep 5; done
它没有任何输出,但sleep
每 2 秒就会终止一次。添加一个cat
:
while true; do timeout 2 sleep 5 | cat; done
现在,它Terminated
每 2 秒输出一次,但cat
看不到它 - 如果我替换cat
为tee somefile
,则文件仍为空。
我尝试2>&1
在命令行的各个位置进行重定向,但无法将输出Terminated
放入文件中。
我认为它们是通过libc
链接到终端外壳而不是循环中的命令输出的。
是否有可能将Terminated
类似的输出放入管道中?
(最终,我想sleep
用 a替换 the ,用脚本替换curl
the ,并处理输出和消息。)cat
awk
curl
Terminated
答案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 5
Terminated
timeout -s KILL 2 sleep 5
Killed
timeout
sleep
所以这才是你所观察到cat
的最重要的Terminated
。现在,如果您替换sleep
为curl
, cat
with awk
,则将timeout
终止curl
和awk
。但这并不重要,因为打印消息的是 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
。