Mantenha os códigos de saída ao capturar SIGINT e similares?

8

Se eu usar trap como descrito, por exemplo no link para capturar ctrl-c (ou similar) e limpeza antes de sair, então estou alterando o código de saída retornado.

Agora, isso provavelmente não fará diferença no mundo real (por exemplo, porque os códigos de saída não são portáteis e, além disso, nem sempre são ambíguos, como discutido em Código de saída padrão quando o processo é encerrado? ), mas ainda estou me perguntando se não há realmente nenhuma maneira de evitar isso e retornar o código de erro padrão para scripts interrompidos?

Exemplo (no bash, mas minha pergunta não deve ser considerada bash-específica):

#!/bin/bash
trap 'echo EXIT;' EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. ' _
trap 'echo SIGINT; exit 1;' INT
read -p 'If you ctrl-c me now my return code will be 1. ' _

Saída:

$ ./test.sh # doing ctrl-c for 1st read
If you ctrl-c me now my return code will be the default for SIGTERM.
$ echo $?
130
$ ./test.sh # doing ctrl-c for 2nd read
If you ctrl-c me now my return code will be the default for SIGTERM.
If you ctrl-c me now my return code will be 1. SIGINT 
EXIT
$ echo $?
1

(Editado para remover para torná-lo mais compatível com POSIX.)

(Editado novamente para torná-lo um script bash, minha pergunta não é específica do shell).

Editado para usar o "INT" portátil para captura em favor do "SIGINT" não portátil.

Editado para remover chaves inúteis e adicionar solução potencial.

Atualização:

Eu resolvi isso agora simplesmente saindo com alguns códigos de erro codificados e prendendo EXIT. Isso pode ser problemático em certos sistemas, porque o código de erro pode ser diferente ou o EXIT trap não é possível, mas no meu caso, tudo bem.

trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
    
por phk 12.10.2015 / 14:26

3 respostas

3

Tudo o que você precisa fazer é alterar o manipulador EXIT dentro do seu manipulador de limpeza. Aqui está um exemplo:

#!/bin/bash
cleanup() {
    echo trapped exit
    trap 'exit 0' EXIT
}
trap cleanup EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. '
    
por 12.10.2015 / 14:42
8

Na verdade, interromper o read interno do bash parece ser um pouco diferente de interromper um comando executado pelo bash. Normalmente, quando você digita trap , $? é definido e você pode preservá-lo e sair com o mesmo valor:

trap 'rc=$?; echo $rc SIGINT; exit $rc' INT
trap 'rc=$?; echo $rc EXIT; exit $rc' EXIT

Se o seu script for interrompido ao executar um comando como sleep ou até mesmo um builtin como wait , você vai ver

130 SIGINT
130 EXIT

e o código de saída é 130. No entanto, para read -p , parece que $? é 0 (na minha versão do bash 4.3.42 de qualquer maneira).

A manipulação de sinais durante read pode ser um trabalho em andamento, de acordo com o arquivo de mudanças na minha versão ... (/ usr / share / doc / bash / CHANGES)

changes between this version, bash-4.3-alpha, and the previous version, bash-4.2-release.

  1. New Features in Bash

    r. When in Posix mode, 'read' is interruptible by a trapped signal. After running the trap handler, read returns 128+signal and throws away any partially-read input.

    
por 12.10.2015 / 14:59
1

Qualquer código de saída de sinal usual estará disponível em $? ao entrar no manipulador de trapping:

sig_handler() {
    exit_status=$?  # Eg 130 for SIGINT, 128 + (2 == SIGINT)
    echo "Doing signal-specific up"
    exit "$exit_status"
}
trap sig_handler INT HUP TERM QUIT

Se houver um trap EXIT separado, você poderá usar a mesma metodologia: manter imediatamente o status de saída passado da limpeza do manipulador de sinal (se houver) e retornar o status de saída salvo.

    
por 29.09.2018 / 18:59