Trap ctrl c não funciona como esperado

2

Eu tenho um código parecido com isto:

{
    trap cleanup SIGHUP SIGINT SIGTERM

    function executed() {
        if [ ${1} -ne 0 ]
        then
            echo "Failed!"
            cleanup
            exit 
        else
            echo "Succeeded!"
        fi
    }

    function cleanup() {
        echo "Cleaning up ..."
        # deleting some files and stuff like that
    }

    bunch of code ...
    ...

} 2>&1 | while IFS= read -r line; do echo "$(date) $line"; done \
>> ldapfe_graceful_$(date '+%Y_%m_%d__%H_%M_%S').log 

Não posso colar todo o meu código, pois não tenho certeza sobre a política da empresa sobre isso e tudo mais, mas as partes mais importantes estão lá.

Pressiono Ctrl + c enquanto esse script está em execução e ele pára imediatamente ou aparece um pequeno ^ C e depois ele para após 5-10 segundos, mas a função de limpeza nunca é chamada.

Eu coloquei todo o código dentro {} para redirecioná-lo bem em um arquivo (eu usei script separado para chamar este e fazer o redirecionamento, mas parece mais difícil de matar aquele e propagar o sinal para este um então eu decidi colocar tudo em chaves aqui).

Tenho certeza de que estou perdendo algo em relação às chaves porque, se eu colocar o trap e a limpeza fora do bloco {}, a função de limpeza será chamada, mas outras partes do código também poderão chamá-lo. não é possível se estiver fora das chaves {}.

EDIT: Eu tentei declarar o trap após a função de limpeza, mas nenhuma alteração.

    
por Luka 30.06.2016 / 16:30

1 resposta

1

  1. Outras partes do código devem poder chamar a função de limpeza, independentemente de estar dentro ou fora das {} chaves, desde que seja declarada antes de sua chamada real (na verdade, não é sobre uma antiga linha de script ) e no mesmo nível de shell bash ( $BASH_SUBSHELL ).

  2. (EDITED) A armadilha pode ser chamada se já foi declarada e tem que ser declarada no mesmo nível de subnível. Aparentemente, o sinal está em cascata, como mostra o código abaixo quando você o executa.

.

#!/usr/bin/env bash

trap "echo ok 0" 2

(
    echo subshell: $BASH_SUBSHELL   
    trap "echo ok 1" 2
    (
        echo subshell: $BASH_SUBSHELL   
        trap "echo ok 2" 2;
        sleep 100
        #now test the trap
    )
)

Resultado:

subshell: 0
subshell: 1
subshell: 2
^Cok 2
ok 1
ok 0

Mas não os tubos:

#!/bin/bash

trap "echo ok 0" 2

{
echo $BASH_SUBSHELL
trap "echo ok 1" 2
} | \
    {
        trap "echo ok 2" 2
        read line; echo $line;
        sleep 100
        #now Ctrl-c
    }

Resultado:

1
^Cok 2
ok 0
  1. As chaves constroem uma função anônima. A função mantém o nível do shell bash, mas não em todos os contextos.

Analise o script abaixo para ilustração. Execute-o em um terminal e veja o que ele produz.

#!/bin/bash

k=k
msg='echo line: $LINENO, \$k: $k, BASH_SUBSHELL: $BASH_SUBSHELL'

eval $msg

{
    k=a
    eval $msg
} &

sleep 1
#job %1 should be done by now
jobs
eval $msg

{
    k=b
    eval $msg
} | {
    read line; echo $line;
    eval $msg
}

eval $msg

{
    k=c
    eval $msg
}

eval $msg

{ trap 'echo -e "\nterminating"; exit;' 2;}

sleep 100 #try out the trap by hitting Ctrl-c
  1. A solução para o seu script é:

a. Mova a armadilha antes do primeiro { .

b. Tente mover a função de limpeza antes do primeiro { usando algumas construções inteligentes como eval (veja no meu script como funciona). Se não for possível, tente construir uma função de proxy nas chaves para uma mais genérica antes delas e corrija o que está faltando em sua chamada na armadilha.

    
por 26.07.2016 / 16:43