Capturar código de saída do comando exit

10

Eu tenho isso em um script bash:

exit 3;

exit_code="$?"

if [[ "$exit_code" != "0" ]]; then
    echo -e "${r2g_magenta}Your r2g process is exiting with code $exit_code.${r2g_no_color}";
    exit "$exit_code";
fi

Parece que ele sairá logo após o comando exit, o que faz sentido. Eu queria saber se existe algum comando simples que pode fornecer um código de saída sem sair imediatamente?

Eu ia adivinhar:

exec exit 3

mas dá uma mensagem de erro: exec: exit: not found. O que eu posso fazer? :)

G-Man diz que 'restabelece Monica'
fonte
1
Sim, exec exit 3não é bom, eu recebo #"exec: exit: not found"
7
Eu não entendo a pergunta. Por que não definir exit_code=3e eliminar a exit 3linha completamente?
precisa saber é
@wjandrea é mais uma questão conceitual do que prático
2
Ainda não faz sentido para mim. Por que haveria um código de saída se você realmente não sair?
Barmar
1
@ Barmar todo processo tem um código de saída. A maioria das pessoas que tenta responder à pergunta está interpretando a pergunta como "com o que posso substituir a 'saída 3' no script para definir a $?variável, mas não sair desse script"?
icarus

Respostas:

32

Se você possui um script que executa algum programa e analisa o status de saída do programa (com  $?), e deseja testá-lo fazendo algo que faz $?com que seja definido com algum valor conhecido (por exemplo,  3), basta fazer

(exit 3)

Os parênteses criam uma subcasca. Em seguida, o exitcomando faz com que o sub-shell saia com o status de saída especificado.

G-Man diz que 'restabelece Monica'
fonte
Além disso, para fins de depuração que seria tão simples de configurar exit_code="3"para testar
Centimane
1
Sim, wjandrea apontou isso ontem.
G-Man diz 'Reinstate Monica'
12

exité um bash embutido, então você não pode exec. De acordo com o manual do bash :

O status de saída do Bash é o status de saída do último comando executado no script. Se nenhum comando for executado, o status de saída será 0.

Juntando tudo isso, eu diria que sua única opção é armazenar o status de saída desejado em uma variável e, exit $MY_EXIT_STATUSquando apropriado.

solarshado
fonte
hmmm, o que você acha da idéia do @ G-man?
2
Talvez eu tenha entendido mal o que você está tentando realizar. Se você está apenas tentando definir $?(embora eu não tenha muita certeza do porquê), isso parece uma resposta sólida. Se você deseja apenas defini-lo com algum valor malsucedido, falseé outra opção.
Solarshado
10

Você pode escrever uma função que retorne o status fornecido como argumento, ou 255se nenhum for fornecido. (Eu o chamo de ret"retorna" seu valor).

ret() { return "${1:-255}"; }

e use retno lugar da sua chamada para exit. Isso evita a ineficiência de criar a subcasca na resposta atualmente aceita.

Algumas medições.

time bash -c 'for i in {1..10000} ; do (exit 3) ; done ; echo $?'

na minha máquina leva cerca de 3,5 segundos.

 time bash -c 'ret(){ return $1 ; } ; for i in {1..10000} ; do ret 3 ; done ; echo $?'

na minha máquina leva cerca de 0,051 segundos, 70 vezes mais rápido. A colocação no manuseio padrão ainda o deixa 60 vezes mais rápido. Obviamente, o loop tem alguma sobrecarga. Se eu mudar o corpo do loop para apenas ser :ou trueo tempo for reduzido para metade para 0,025, um loop completamente vazio será uma sintaxe inválida. A adição ;:ao loop mostra que esse comando mínimo leva 0,007 segundos, portanto a sobrecarga do loop é de cerca de 0,018. Subtrair essa sobrecarga dos dois testes mostra que a retsolução é 100 vezes mais rápida.

Obviamente, essa é uma medida sintética, mas as coisas se somam. Se você torna tudo 100 vezes mais lento do que o necessário, acaba com sistemas lentos. 0,0

Icaro
fonte
2
@iBug O espaço extra não é necessário.
Icarus
Bom ponto sobre a ineficiência de criar o sub-shell. Eu li que algumas conchas podem ser inteligentes o suficiente para otimizar o fork em casos como este, mas essa festança não é uma delas.
G-Man diz 'Reinstate Monica'
3

Sobre exec exit 3... ele tentaria executar um comando externo chamado exit, mas não há um, então você recebe o erro. Ele deve ser um comando externo, em vez de um incorporado ao shell, pois o exec substitui completamente. O que também significa que, mesmo se você tivesse um comando externo chamado exit, exec exit 3não retornaria para continuar seu script de shell, pois o shell não estaria mais lá .

ilkkachu
fonte
1
Eu acho que você poderia fazer exec bash -c "exit 3", mas no momento não consigo pensar em nenhum motivo para fazer isso, em vez de apenas exit 3.
David Z
1
@DavidZ, em qualquer caso, exec'ing ou apenas exit' ing vai parar o script, o que não parece ser o que a pergunta queria.
Ilkkachu
3

Você pode fazer isso com o Awk:

awk 'BEGIN{exit 9}'

Ou Sed:

sed Q9 /proc/stat
Steven Penny
fonte
... ou com uma concha:sh -c 'exit 9'
ilkkachu
1
@ilkkachu se você estiver indo para fazer que você poderia muito bem fazer o (exit 9)na resposta aceita
Steven Penny