向命令管道发送信号拆除整个管道

向命令管道发送信号拆除整个管道

我有一个两个过程的简单示例

第一个是一个简单的循环,它进行一些处理

#!/bin/bash
function signalHandler() {
    echo "sig: $1 received ==> exit"
    for i in {1..5}; do
        echo "cleanup $i %"
        sleep 1
    done
    trap SIGINT
    kill -INT $$
}

trap signalHandler SIGUSR2

for i in {1..100000}; do
    echo "doing stuff $i %"
    sleep 0.1
done

我像这样启动了脚本:

./script.sh | grep "wow"

我附加了一个辅助 grep 命令只是为了演示。

当我仅向进程发送 USR2 信号grep( kill USR2 $(pgrep grep)) 时,整个管道被拆除 (?)。为什么script.sh不继续?

其次,当我向整个进程组发送 USR2 信号(类似于kill USR2 -$!)时,显然会发生同样的情况,因为grep退出速度很快,它会破坏整个管道而不让script.sh执行signalHandler.我想我有一些误解,这应该如何运作?

多谢

答案1

正如 @muru 评论的那样,问题是你的脚本不处理SIGPIPE.

以下更改将允许脚本按预期终止:

function signalHandler() {
    echo "sig: $1 received ==> exit" >&2   # <--
    for i in {1..5}; do
        echo "cleanup $i %" >&2   # <--
        sleep 1
    done
    trap SIGINT
    kill -INT $$
}

trap signalHandler SIGUSR2
trap signalHandler SIGPIPE   # <--

为了使示例简单,使用相同的信号处理程序来处理SIGPIPE.echo信号处理程序的输出被重定向到,STDERR因为STDOUT显然在 被捕获时已经被破坏了SIGPIPE

输出:

$ ./script.sh | grep wow
./script.sh: line 16: echo: write error: Broken pipe
sig:  received ==> exit
cleanup 1 %
cleanup 2 %
cleanup 3 %
cleanup 4 %
cleanup 5 %

User defined signal 2: 31

管道中断(第一条错误消息),但信号处理程序在script.sh退出之前完成。

如果你想完全忽略SIGPIPE,你需要为信号添加一个虚拟处理程序,并将主echo语句的 STDERR 重定向到/dev/null

function signalHandler2() {
    :
}

trap signalHandler SIGUSR2
trap signalHandler2 SIGPIPE

# ...skip...

for i in {1..100000}; do
    echo "doing stuff $i %" 2>/dev/null

相关内容