パイプライン全体を解体するには、コマンドパイプラインに信号を送信します。

パイプライン全体を解体するには、コマンドパイプラインに信号を送信します。

2つのプロセスの簡単な例があります。

最初は、いくつかの処理を実行する単純なループです。

#!/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コマンドを添付しました。

grepUSR2信号()のみがプロセスに送信されると、kill USR2 $(pgrep grep)パイプ全体が破れます(?)。続行しませんかscript.sh

第二に、USR2信号をプロセスグループ全体に送信すると同じことが起こります(例:kill USR2 -$!Operation:grepscript.shsignalHandler

ありがとう

ベストアンサー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   # <--

例を簡単にするために、同じシグナルハンドラが処理に使用されますSIGPIPEecho信号ハンドラの出力は、キャッチすると明らかに破壊されるSTDERRため、リダイレクトされます。STDOUTSIGPIPE

出力:

$ ./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ダミーハンドラを追加し、デフォルトのステートメントechoSTDERRを次にリダイレクトする必要があります/dev/null

function signalHandler2() {
    :
}

trap signalHandler SIGUSR2
trap signalHandler2 SIGPIPE

# ...skip...

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

おすすめ記事