envia sinal para o tubo de comando rasga todo o tubo

1

Eu tenho um exemplo simples de dois processos

o primeiro é um loop simples que faz algum processamento

#!/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

Eu lancei o script assim:

./script.sh | grep "wow"

onde eu anexei um comando grep auxiliar apenas para demonstração.

Quando eu envio um sinal USR2 para o processo grep ( kill USR2 $(pgrep grep) ) apenas, o pipe inteiro é demolido (?). Por que script.sh não continua?

Em segundo lugar, quando envio um sinal USR2 para todo o grupo de processos (algo parecido com kill USR2 -$! ), obviamente o mesmo acontece, pois grep fecha rápido, ele rasga todo o canal sem deixar script.sh executar o% código%. Acho que tenho algum mal entendido de como isso deve funcionar?

Muito obrigado

    
por Gabriel 18.04.2016 / 23:16

1 resposta

4

Como @muru comentou, o problema é que seu script não manipula SIGPIPE .

As alterações a seguir permitirão que o script termine conforme pretendido:

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   # <--

Para manter o exemplo simples, o mesmo manipulador de sinal é usado para manipular SIGPIPE . A saída echo do manipulador de sinal é redirecionada para STDERR , já que STDOUT obviamente já está corrompido quando o SIGPIPE é capturado.

Saída:

$ ./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

As quebras de tubo (primeira mensagem de erro), mas o manipulador de sinal completam antes de script.sh sair.

Se você quiser ignorar completamente o SIGPIPE , precisará adicionar um manipulador simulado para o sinal e redirecionar STDERR para a instrução echo principal para /dev/null :

function signalHandler2() {
    :
}

trap signalHandler SIGUSR2
trap signalHandler2 SIGPIPE

# ...skip...

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

Tags