O script Bash não vê SIGHUP?

11

Eu tenho o seguinte script:

#!/bin/bash
echo "We are $$"
trap "echo HUP" SIGHUP
cat    # wait indefinitely

Quando envio SIGHUP(usando kill -HUP pid), nada acontece.

Se eu mudar um pouco o script:

#!/bin/bash
echo "We are $$"
trap "kill -- -$BASHPID" EXIT    # add this
trap "echo HUP" SIGHUP
cat    # wait indefinitely

... então o script faz a echo HUPcoisa certa quando sai (quando pressiono Ctrl + C):

roger@roger-pc:~ $ ./hupper.sh 
We are 6233
^CHUP

O que está acontecendo? Como devo enviar um sinal (não necessariamente precisa ser SIGHUP) para esse script?

Roger Lipscombe
fonte
4
O sinal será entregue e o manipulador de sinal será executado quando o catprocesso terminar. Experimente o seu script original e pressione Ctrl+Dpara sair do catprocesso. Enquanto o catprocesso estiver em primeiro plano, o HUPsinal não será acionado. Tente novamente com catsubstituído por read(um shell interno).
Kusalananda
Perfeito. Alguém gosta de transformar isso em resposta?
Roger Lipscombe
Sei que funciona dessa maneira, mas deixarei alguém que tenha mais discernimento do que eu nos porquês e por onde fazer a resposta.
Kusalananda
Eu usei while true; do read; doneno final, caso contrário, a inserção de texto também fará com que ele saia e quero que saia em Ctrl + C.
Roger Lipscombe

Respostas:

21

O manual do Bash declara:

Se o bash estiver aguardando a conclusão de um comando e receber um sinal para o qual uma captura foi configurada, a captura não será executada até que o comando seja concluído.

Isso significa que, apesar do sinal ser recebido bashquando você o envia, sua armadilha no SIGHUP será chamada apenas quando catterminar.

Se esse comportamento for indesejável, use bashbuiltins (por exemplo, read+ printfem um loop em vez de cat) ou use trabalhos em segundo plano (consulte a resposta de Stéphane ).

xhienne
fonte
9

O @xhienne já explicou o motivo , mas se você deseja que o sinal atue imediatamente (e não saia do script), você pode alterar seu código para:

#! /bin/bash -
interrupted=true
trap 'interrupted=true; echo HUP' HUP

{ cat <&3 3<&- & pid=$!; } 3<&0

while
  wait "$pid"
  ret=$?
  "$interrupted"
do
  interrupted=false
done
exit "$ret"

A pequena dança dos descritores de arquivo é contornar o fato de que o bashredirecionamento do stdin é /dev/nullpara comandos iniciados em segundo plano.

Stéphane Chazelas
fonte
Isso funciona porque o bloco de código é executado em um subshell?
Pysis 23/08/17