bash 3 和 4 之间的 SIGINT 处理差异

bash 3 和 4 之间的 SIGINT 处理差异

我有一个在 bash 4.3 中运行良好的脚本,但在 bash 3.2 中却给了我意想不到的行为。这是一个简化版本:

set -o errexit -o pipefail

task() {
    local name=${1}
    local duration=${2}
    trap 'echo "[${SECONDS} secs] ${name}: SIGINT"; exit 255' INT
    echo "[${SECONDS} secs] ${name}: Running"
    sleep "${duration}"
    echo "[${SECONDS} secs] ${name}: Done"
}

trap 'echo "[${SECONDS} secs] SIGINT"; exit 255' INT
task 'Task 1' 5 &
task 'Task 2' 5 &
wait
echo "[${SECONDS} secs] Done"

以下是使用 bash 4.3 (4.3.42(1)-release) 运行 CTRL-C 两秒后的输出:

[0 secs] Task 1: Running
[0 secs] Task 2: Running
^C[2 secs] SIGINT
[2 secs] Task 2: SIGINT
[2 secs] Task 1: SIGINT
prompt>

同样的事情,但对于 bash 3.2 (3.2.57(1)-release):

[0 secs] Task 1: Running
[0 secs] Task 2: Running
^C[2 secs] SIGINT
prompt> [5 secs] Task 2: Done
[5 secs] Task 1: Done

是否存在阻止上述脚本在 bash 3.2 下正常工作的已知问题?是否存在解决方法?

以下是我尝试过的一些事情:

  • 父级中没有信号处理程序:

    # bash 4.3
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] Task 2: SIGINT
    [2 secs] Task 1: SIGINT
    prompt>
    
    # bash 3.2
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C
    prompt> [5 secs] Task 2: Done
    [5 secs] Task 1: Done
    
  • 根本没有信号处理程序:

    # bash 4.3
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C
    prompt>
    
    # bash 3.2
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C
    prompt> [5 secs] Task 2: Done
    [5 secs] Task 1: Done
    
  • 父级中的信号处理程序使用 SIGINT ( ) 杀死进程组kill -INT -- -$$

    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    [2 secs] Task 2: SIGINT
    [2 secs] Task 1: SIGINT
    prompt>
    
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    prompt> [5 secs] Task 2: Done
    [5 secs] Task 1: Done
    
  • 父级中的信号处理程序使用 SIGTERM 终止进程组(任务捕获 SIGTERM):

    # bash 4.3
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    [2]    92813 terminated  bash minimal_example.sh
    prompt>
    
    # bash 3.2
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    Terminated: 15
    Terminated: 15
    [2 secs] Task 2: SIGTERM
    [2 secs] Task 1: SIGTERM
    [1]    92836 terminated  /bin/bash minimal_example.sh
    prompt>
    

最后一个是最接近在 3.2 中正常工作的,相同的代码在 4.3 中的行为有所不同。

答案1

您可能是bash经常影响make用户的众所周知问题的受害者。

我还没有检查 bash 4,但bash 3在脚本内错误地执行了作业控制。这通常会导致包含多个子目录循环的 makefile 不容易被杀死,^C因为子进程在单独的进程组中运行,即使这些命令不是交互式命令。

smake包括一个解决方法,/bin/sh并将bashSIGINT 显式转发到当前运行命令的进程组。但这是用C.

由于没有标准的 UNIX 命令来检索子进程组,因此无法使用脚本中的常用 shell 来实现相同的功能。

相关内容