Considere este pequeno script. Ele configura dois manipuladores de sinal; um para USR1
e outro para USR2
. Em seguida, inicia uma sessão de shell interativa.
#!/bin/sh
sigusr1_handler () {
variable=1
printf "SIGUSR1: variable is now %d\n" "$variable"
}
sigusr2_handler () {
variable=2
printf "SIGUSR2: variable is now %d\n" "$variable"
}
variable=0
printf "At beginning, variable is %d\n" "$variable"
trap 'sigusr1_handler' USR1
trap 'sigusr2_handler' USR2
/bin/sh
printf "At end, variable is %d\n" "$variable"
Executando:
$ ./script.sh
At beginning, variable is 0
$ kill -s USR1 $PPID
$ kill -s USR2 $PPID
$ kill -s USR1 $PPID
$ exit
SIGUSR1: variable is now 1
SIGUSR2: variable is now 2
At end, variable is 2
A primeira coisa que notei é que o shell pai não está manipulando os sinais até que o shell filho termine. Eu achei que isso é documentado pelo POSIX, então eu sou o culpado por não ler a documentação corretamente.
A segunda coisa que notei foi que o sinal não está na fila. Isso pode ser um conhecimento realmente básico, mas me escapou. Suponho que, enquanto o processo filho está sendo executado, os sinais gerados estão pendentes e, se um sinal pendente for gerado novamente , ele será simplesmente ignorado.
Meu problema é que preciso para que os sinais sejam entregues aos manipuladores de sinais do processo pai enquanto o shell interativo (o processo filho) está em execução. Eu preciso disso porque quero tomar decisões com base no valor $variable
após o término do processo filho, e se os sinais forem gerados na mesma ordem que na sessão interativa acima, $variable
deve ter o valor 1 no final do script.
Então, minha solução ingênua era iniciar o processo filho como um trabalho em segundo plano assíncrono:
/bin/sh &
wait
(Eu sei que preciso verificar o valor de retorno de wait
no caso de entrega de sinal, mas vou configurar isso depois.)
Isso não funciona. O processo filho sai imediatamente:
$ sh -x script.sh
+ variable=0
+ printf At beginning, variable is %d\n 0
At beginning, variable is 0
+ trap sigusr1_handler USR1
+ trap sigusr2_handler USR2
+ wait
+ /bin/sh
+ printf At end, variable is %d\n 0
At end, variable is 0
(Parece que o wait
é executado antes do shell na saída de rastreio acima, mas eu estou fazendo isso na ordem correta no script.)
O uso de /bin/sh -i &
não altera nada. Fiz outras tentativas com /bin/sh -s
e redirecionei /dev/stdin
para ele, e combinações desses ( -i -s
), mas sem sucesso.
Então agora a minha pergunta é: Como posso iniciar um shell interativo a partir de um script como um processo assíncrono (isto é, aceitar entrada como qualquer shell interativo) para que seu processo pai possa ter sinais entregues assim que eles são gerados? Ou, outro design é possível?