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.