Por que minha armadilha não disparou?

2

Dado um script que echo ao receber um sinal SIGSTOP ou SIGHUP :

$cat test.sh 
function clean_up {
    echo "cleaning up!"
}

echo 'starting!'

trap clean_up SIGSTOP SIGHUP

sleep 100

Eu corri em segundo plano:

$./test.sh > output &
[4] 42624

Então, eu o matei com -1 , ou seja, SIGHUP

$kill -1 42624

Mas o trap não funcionou como eu esperava, ou seja, o arquivo output não tem cleaning up! em seu conteúdo.

$cat output 
starting!

O que aconteceu?

    
por Kevin Meredith 11.05.2016 / 16:47

3 respostas

5

Na verdade, ele foi impresso, mas você precisa esperar 100 segundos para ver o resultado.

Você disse:

$./test.sh > output &
[4] 42624

Se você marcar ps aux , receberá algo semelhante a:

xiaobai  42624  0.0  0.1 118788  5492 pts/3    S    04:07   0:00 /bin/bash
xiaobai  42626  0.0  0.0 108192   668 pts/3    S    04:07   0:00 sleep 100

Seu processo de script principal de / bin / bash, PID 42624 ainda está esperando pelo término do sleep 100. Mesmo o processo principal recebeu o sinal 1, ele tem que esperar sleep 100 terminar primeiro, depois é a vez dele executar sua tarefa, ou seja, echo "cleaning up!" .

Você pode tornar o processo de suspensão um processo em segundo plano. Nesse caso, o processo de script pode executar echo "cleaning up!" sem aguardar o sleep process , se e somente se o processo do script não sair ainda.

Podemos provar que o script conceitual (por exemplo, está aguardando sleep antes do sinal de identificador) por meio desse script:

function clean_up {
    echo "cleaning up!"
}

echo 'starting!'

trap clean_up SIGHUP
sleep 5000 &
echo 1
sleep 20
echo 2
sleep 10
echo 3

Execute este script em ./test.sh > output como de costume, depois use ps aux para descobrir que /bin/bash PID é 23311 e, em seguida, faça kill -1 23311 . Ao mesmo tempo cat output para conhecer o estágio, ou seja, quando o script entrar em sleep 20 após o eco 1, envie kill -1 23311 , agora espere 2 sair, você notará que a "limpeza" foi impressa em conjunto antes de 2 Finalmente, é a vez de echo 3 e a saída do script.

$ cat output                                                                                            
starting!
1
cleaning up!
2
3
$ 

O experimento acima provou que o script recebe o sinal SIGHUP e executa o manipulador de sinal depois que todo o processo de foreground anterior é feito e, por sua vez, sem esperar o processo em segundo plano.

A história se torna interessante, com seu script original, e se você fizer kill -1 PID_of_sleep_100 ?

Ele sairá de todos os processos sem impressão, porque o processo de suspensão não retorna SIGHUP para o processo de script.

Portanto, há uma solução para sua tarefa, você pode fazer kill -1 PPID (processo de script) para reconhecer SIGHUP no processo de script e, em seguida, kill -1 PID (processo de suspensão). Agora o processo de script fará o manipulador SIGHUP antes de sair, feliz hacking:)

Nem todos os sinais são iguais, por ex. SIGKILL não é permitido capturar . Se você matar -9 o processo de script, o processo de suspensão ainda estará em execução e seu PID pai será 1 (verifique por ps -ef ).

[UPDATE]:

Normalmente, kill -N script_PID mata diretamente o script se o sinal N não prender no seu script . Mas tenha cuidado com o SIGINT, kill -2 script_PID não irá matar diretamente, mesmo que o seu script não o prenda. Seu roteiro irá aguardar seu processo filho (por exemplo, dormir 10) feito. Agora, suponha que você faça vários kill em script_PID, ou seja, kill -2 script_PID AND kill -user-defined_trap_N script_PID e, em seguida:

  1. Se o sleep retornar normalmente após 10 segundos de espera OU matar por outro sinal diferente de 2 , seu script ignorará o sinal 2 em cache quando retornar, e então executará o função defined_trap_N.
  2. Mas se dormir matar pelo sinal 2 , seu script executará o manipulador SIGINT integrado quando retornar e, em seguida, eliminará diretamente sem executar user-defined_trap_N.
por 11.05.2016 / 23:06
1

A página man do bash declara

If bash is waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes.

No seu exemplo, o trap não será executado até que o sleep 100 seja concluído.

    
por 12.05.2016 / 00:30
-2

trap funciona com números de sinal (ou seja, trap clean_up 1 ) ou com nomes sem prefixo "sig" (ou seja, trap clean_up HUP ).

Além disso, SIGSTOP não pode ser interceptado .

    
por 11.05.2016 / 16:58