Unix / Linux - sinais e armadilhas
Neste capítulo, discutiremos em detalhes sobre sinais e armadilhas no Unix.
Os sinais são interrupções de software enviadas a um programa para indicar que ocorreu um evento importante. Os eventos podem variar de solicitações do usuário a erros de acesso ilegal à memória. Alguns sinais, como o sinal de interrupção, indicam que um usuário pediu ao programa para fazer algo que não está no fluxo normal de controle.
A tabela a seguir lista os sinais comuns que você pode encontrar e deseja usar em seus programas -
Nome do Sinal | Número do Sinal | Descrição |
---|---|---|
SIGHUP | 1 | Desligamento detectado no terminal de controle ou morte do processo de controle |
SIGINT | 2 | Emitido se o usuário enviar um sinal de interrupção (Ctrl + C) |
SIGQUIT | 3 | Emitido se o usuário enviar um sinal de saída (Ctrl + D) |
SIGFPE | 8 | Emitido se uma operação matemática ilegal for tentada |
SIGKILL | 9 | Se um processo receber este sinal, ele deve ser encerrado imediatamente e não realizará nenhuma operação de limpeza |
SIGALRM | 14 | Sinal de despertador (usado para temporizadores) |
SIGTERM | 15 | Sinal de encerramento de software (enviado por kill por padrão) |
Lista de Sinais
Existe uma maneira fácil de listar todos os sinais suportados pelo seu sistema. Basta emitir okill -l comando e exibiria todos os sinais suportados -
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT
17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU
25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN
35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4
39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6
59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
A lista real de sinais varia entre Solaris, HP-UX e Linux.
Ações padrão
Cada sinal tem uma ação padrão associada a ele. A ação padrão para um sinal é a ação que um script ou programa executa ao receber um sinal.
Algumas das possíveis ações padrão são -
Encerre o processo.
Ignore o sinal.
Dump core. Isso cria um arquivo chamadocore contendo a imagem de memória do processo ao receber o sinal.
Pare o processo.
Continue um processo interrompido.
Enviando sinais
Existem vários métodos de entrega de sinais a um programa ou script. Um dos mais comuns é um usuário digitarCONTROL-C ou o INTERRUPT key enquanto um script está sendo executado.
Quando você pressiona o Ctrl+C chave, um SIGINT é enviado para o script e, de acordo com a ação padrão definida, o script termina.
O outro método comum de entrega de sinais é usar o kill command, cuja sintaxe é a seguinte -
$ kill -signal pid
Aqui signal é o número ou nome do sinal a ser entregue e pidé o ID do processo para o qual o sinal deve ser enviado. Por exemplo -
$ kill -1 1001
O comando acima envia o HUP ou sinal de desligamento para o programa que está sendo executado com process ID 1001. Para enviar um sinal de eliminação para o mesmo processo, use o seguinte comando -
$ kill -9 1001
Isso mata o processo em execução com process ID 1001.
Sinais de Trapping
Quando você pressiona a tecla Ctrl + C ou Break em seu terminal durante a execução de um programa shell, normalmente esse programa é encerrado imediatamente e seu prompt de comando retorna. Isso pode nem sempre ser desejável. Por exemplo, você pode acabar deixando um monte de arquivos temporários que não serão limpos.
Capturar esses sinais é muito fácil, e o comando trap tem a seguinte sintaxe -
$ trap commands signals
Aqui, o comando pode ser qualquer comando válido do Unix, ou mesmo uma função definida pelo usuário, e o sinal pode ser uma lista de qualquer número de sinais que você deseja capturar.
Existem dois usos comuns para trap em scripts de shell -
- Limpe os arquivos temporários
- Ignorar sinais
Limpando Arquivos Temporários
Como um exemplo do comando trap, o seguinte mostra como você pode remover alguns arquivos e sair se alguém tentar abortar o programa do terminal -
$ trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2
Do ponto no programa de shell em que esta armadilha é executada, os dois arquivos work1$$ e dataout$$ será removido automaticamente se o sinal número 2 for recebido pelo programa.
Portanto, se o usuário interromper a execução do programa após a execução dessa armadilha, você pode ter certeza de que esses dois arquivos serão limpos. oexit comando que segue o rm é necessário porque sem ele, a execução continuaria no programa no ponto em que parou quando o sinal foi recebido.
O sinal número 1 é gerado para hangup. Alguém desliga intencionalmente a linha ou a linha é desconectada acidentalmente.
Você pode modificar a armadilha anterior para também remover os dois arquivos especificados, neste caso, adicionando o sinal número 1 à lista de sinais -
$ trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2
Agora, esses arquivos serão removidos se a linha for desligada ou se a tecla Ctrl + C for pressionada.
Os comandos especificados para trap devem ser colocados entre aspas, se contiverem mais de um comando. Observe também que o shell varre a linha de comando no momento em que o comando trap é executado e também quando um dos sinais listados é recebido.
Assim, no exemplo anterior, o valor de WORKDIR e $$será substituído no momento em que o comando trap for executado. Se você quiser que essa substituição ocorra no momento em que o sinal 1 ou 2 foi recebido, você pode colocar os comandos entre aspas simples -
$ trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2
Ignorando sinais
Se o comando listado para trap for nulo, o sinal especificado será ignorado quando recebido. Por exemplo, o comando -
$ trap '' 2
Isso especifica que o sinal de interrupção deve ser ignorado. Você pode querer ignorar certos sinais ao realizar uma operação que você não deseja ser interrompida. Você pode especificar vários sinais a serem ignorados da seguinte forma -
$ trap '' 1 2 3 15
Observe que o primeiro argumento deve ser especificado para que um sinal seja ignorado e não é equivalente a escrever o seguinte, que tem um significado separado próprio -
$ trap 2
Se você ignorar um sinal, todos os subshells também ignoram esse sinal. No entanto, se você especificar uma ação a ser executada no recebimento de um sinal, todos os subshells ainda realizarão a ação padrão no recebimento desse sinal.
Redefinindo armadilhas
Depois de alterar a ação padrão a ser executada ao receber um sinal, você pode alterá-la novamente com a armadilha se simplesmente omitir o primeiro argumento; então -
$ trap 1 2
Isso restaura a ação a ser tomada no recebimento dos sinais 1 ou 2 de volta ao padrão.