Como faço para capturar SIGQUIT corretamente em um script bash?
Pergunta
Posso escrever scripts de shell que capturam SIGINT
perfeitamente, mas não consigo capturar SIGQUIT
.
#!/bin/bash
function die {
echo "Dying on signal $1"
exit 0
}
trap 'die "SIGINT"' SIGINT
trap 'die "SIGQUIT"' SIGQUIT
while true; do
echo "sleeping..."
sleep 5
done
Executar este script e pressionar CTRL-C
tem o efeito desejado, mas pressionar CTRL-\
(que, pelo que entendi, deve acionar SIGQUIT
) não faz nada, exceto imprimir ^\
no terminal. Por quê?
Tenho duas teorias em execução. A primeira é que a semântica de SIGINT
e SIGQUIT
são diferentes, de modo que SIGQUIT
só é enviado para o processo filho sleep
, enquanto SIGINT
é enviado para o processo filho e o processo bash pai. Se for esse o caso, onde está documentado?
Minha segunda teoria é que o bash não apenas ignora (ou seja, tem um manipulador autônomo para) SIGQUIT
por padrão (como a página do manual sugere), mas também não permite que seja interceptado. Essa teoria se sobrepõe à primeira, já que pode ser o caso de SIGQUIT
indo para o pai e o filho, mas o pai (bash
) simplesmente não consegue prendê-lo. Se for esse o caso, há alguma maneira de capturar SIGQUIT
em um script bash? ... talvez algum shopt
que eu possa definir?
Editar: isto é no Ubuntu 10.10 no gnome-terminal 2.32.0 executando o bash 4.1.5, e sim ^\
está configurado para emitir SIGQUIT (conforme relatado por stty -a
e confirmado pela emissão de ^\
SIGQUITs para outros programas como ping
).
ATUALIZAÇÃO:
Acabei de descobrir que o problema deve ser devido ao gnome-terminal. Se eu executar este script a partir de um console virtual (ou seja, ctrl-alt-f1
para sair do X), ele intercepta SIGQUIT perfeitamente bem quando pressiono ^\
. Mesmo bash e tudo, então a única diferença deve ser o emulador de terminal. Então agora minha pergunta é: como posso configurar o gnome-terminal para se comportar como o console virtual a esse respeito? Eu diff
'd as saídas de stty -a
no console virtual e no gnome-terminal e, embora haja diferenças, nada parece imediatamente relevante (por exemplo, ambos têm quit = ^\;
).
ATUALIZAÇÃO 2:
Outro experimento. Simplesmente execute $ sleep 60
no gnome-terminal; pressione ^\
e o sinal não será capturado. Agora execute $ sleep 60
no console virtual; pressione ^\
e o sinal é capturado - o processo imprime Quit
e sai. Mas agora execute $ ping google.com
no gnome-terminal e pressione ^\
- o sinal é capturado e tratado conforme o esperado. Portanto, há algo estranho no gnome-terminal de tal forma que o SIGQUIT pode ser capturado por alguns programas, mas não por outros, mesmo que esses outros o façam o capturem quando invocados do console virtual. Talvez eu deva apenas atualizar meu terminal gnome.
Solução
Só posso presumir que era algum tipo de bug no gnome-terminal 2.32.0;Desde então, atualizei para o Ubuntu 11.04, com gnome-terminal 2.32.1 (e bash 4.2.8) e SIGQUIT agora está preso como esperado.
Outras dicas
Eu observo o mesmo comportamento no Fedora 19 com XFCE: de acordo com ps s
, bash no terminal xfce4 tem SIGQUIT ignorado, executando yes >/dev/null &
e então ps s
mostra que mesmo um subprocesso tem SIGQUIT ignorado.Quando eu (do mesmo terminal) executo ssh localhost
, o shell na sessão ssh também tem SIGQUIT ignorado, mas yes >/dev/null &
não.
Dado o comentário acima que menciona o gnome-terminal, acho que o bug está na parte comum dos dois terminais: a biblioteca vte
.O meu é vte-0.28.2-9.fc19.x86_64
.