脚本使用eval启动的子进程不会在ctrl + c上中断

时间:2017-06-24 08:01:06

标签: linux bash macos

我知道之前在SO上已经提出了类似的问题(例如here),但我无法让它适用于我的案例。

我有一个名为kubetail的bash脚本,它评估从脚本开始的一组后台命令,如下所示:

CMD="cat <( eval "${command_to_tail}" )"
eval "$CMD"

其中command_to_tail调用多个子进程(kubectl)并将其输出聚合为一个流。问题是在ctrl+c期间按下eval时,它不会在主脚本停止时中断子进程。例如,当我在中断脚本后运行ps -Af | grep kubectl 时会显示此信息(kubectl由我的脚本生成):

$ ps -Af | grep kubectl
501 85748 85742   0  9:48AM ttys014    0:00.16 kubectl --context= logs pod-4074277481-3tlx6 core -f --since=10s --namespace=
501 85750 85742   0  9:48AM ttys014    0:00.17 kubectl --context= logs pod-4074277481-9r224 core -f --since=10s --namespace=
501 85752 85742   0  9:48AM ttys014    0:00.16 kubectl --context= logs pod-4074277481-hh9bz core -f --since=10s --namespace=

我尝试了各种形式的trap - INT,但我找不到能够杀死ctrl+c上所有子流程的解决方案。有什么建议吗?

1 个答案:

答案 0 :(得分:1)

您遇到的问题是由于所有子进程都在自己的进程ID下独立运行。当您发出ctrl + c时,您试图取消在其原始PID下运行的原始脚本。子流程不受影响。一个简单的类似例子是:

#!/bin/bash

declare -i cnt=1
while [ "$cnt" -lt 100 ]; do
    printf "iteration: %2d\n" "$cnt"
    sleep 5
    ((cnt++))
done

当您运行脚本然后尝试取消脚本时,控制很可能在sleep PID内,并且ctrl + c无效。如果您想要在任何时候控制取消脚本,那么您需要让每个子进程识别父进程收到SIGINT以了解发生的中断。在某些情况下(与上面sleep一样),在脚本中调用时不能直接执行,因为按ctrl + c不会影响sleep进程(每次迭代都会更改)

在所有情况下都没有解决这个问题的灵丹妙药,因为所需的内容在很大程度上取决于你对子进程中可以做什么的控制类型以及你的父脚本是否会完全迭代每次迭代检查(就像临时文件的存在一样)是一种可行的解决方案。