Os processos podem chamar a chamada do _exit()
sistema (no Linux, consulte também exit_group()
) com um argumento inteiro para relatar um código de saída ao pai. Embora seja um número inteiro, apenas os 8 bits menos significativos estão disponíveis para o pai (a exceção é quando se usa waitid()
ou manipula SIGCHLD no pai para recuperar esse código , embora não no Linux).
O pai normalmente faz um wait()
ou waitpid()
para obter o status de seu filho como um número inteiro (embora também waitid()
possa ser usada uma semântica um pouco diferente).
No Linux e na maioria dos Unices, se o processo terminar normalmente, os bits 8 a 15 desse número de status conterão o código de saída conforme passado exit()
. Caso contrário, os 7 bits menos significativos (0 a 6) conterão o número do sinal e o bit 7 será definido se um núcleo for despejado.
perl
, $?
por exemplo, contém esse número, conforme definido por waitpid()
:
$ perl -e 'system q(kill $$); printf "%04x\n", $?'
000f # killed by signal 15
$ perl -e 'system q(kill -ILL $$); printf "%04x\n", $?'
0084 # killed by signal 4 and core dumped
$ perl -e 'system q(exit $((0xabc))); printf "%04x\n", $?'
bc00 # terminated normally, 0xbc the lowest 8 bits of the status
Os shells tipo Bourne também fazem o status de saída do último comando de execução em sua própria $?
variável. No entanto, ele não contém diretamente o número retornado por waitpid()
, mas uma transformação e é diferente entre os shells.
O que é comum entre todos os shells é que $?
contém os 8 bits mais baixos do código de saída (o número passado para exit()
) se o processo terminar normalmente.
A diferença é quando o processo é finalizado por um sinal. Em todos os casos, e isso é exigido pelo POSIX, o número será maior que 128. O POSIX não especifica qual pode ser o valor. Na prática, porém, em todas as conchas semelhantes a Bourne que eu conheço, os 7 bits mais baixos $?
conterão o número do sinal. Mas, onde n
está o número do sinal,
em ash, zsh, pdksh, bash, a concha Bourne, $?
é 128 + n
. O que isto significa é que nessas conchas, se você receber um $?
dos 129
, você não sabe se é porque o processo foi encerrado com exit(129)
ou se ele foi morto pelo sinal 1
( HUP
na maioria dos sistemas). Mas a lógica é que os shells, quando saem por si mesmos, por padrão, retornam o status de saída do último comando encerrado. Ao garantir que $?
nunca seja maior que 255, isso permite ter um status de saída consistente:
$ bash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
bash: line 1: 16720 Terminated sh -c "kill \$\$"
8f # 128 + 15
$ bash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
bash: line 1: 16726 Terminated sh -c "kill \$\$"
8f # here that 0x8f is from a exit(143) done by bash. Though it's
# not from a killed process, that does tell us that probably
# something was killed by a SIGTERM
ksh93
, $?
É 256 + n
. Isso significa que, a partir de um valor, $?
você pode diferenciar entre um processo morto e não morto. As versões mais recentes de ksh
, na saída, se $?
eram maiores que 255, se matam com o mesmo sinal para poder relatar o mesmo status de saída ao pai. Embora isso pareça uma boa ideia, isso significa que ksh
irá gerar um despejo de núcleo extra (potencialmente substituindo o outro) se o processo for interrompido por um sinal de geração de núcleo:
$ ksh -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
ksh: 16828: Terminated
10f # 256 + 15
$ ksh -c 'sh -c "kill -ILL \$\$"; exit'; printf '%x\n' "$?"
ksh: 16816: Illegal instruction(coredump)
Illegal instruction(coredump)
104 # 256 + 15, ksh did indeed kill itself so as to report the same
# exit status as sh. Older versions of `ksh93` would have returned
# 4 instead.
Onde você pode até dizer que há um bug é que se ksh93
mata mesmo que $?
provenha de return 257
uma função:
$ ksh -c 'f() { return "$1"; }; f 257; exit'
zsh: hangup ksh -c 'f() { return "$1"; }; f 257; exit'
# ksh kills itself with a SIGHUP so as to report a 257 exit status
# to its parent
yash
. yash
oferece um compromisso. Retorna 256 + 128 + n
. Isso significa que também podemos diferenciar entre um processo morto e um que terminou corretamente. E ao sair, será relatado 128 + n
sem ter que se suicidar e os efeitos colaterais que pode ter.
$ yash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
18f # 256 + 128 + 15
$ yash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
8f # that's from a exit(143), yash was not killed
Para obter o sinal do valor de $?
, a maneira portátil é usar kill -l
:
$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM
(para portabilidade, você nunca deve usar números de sinal, apenas nomes de sinal)
Nas frentes não Bourne:
csh
/ tcsh
e o fish
mesmo que o shell Bourne, exceto que o status está em $status
vez de $?
(observe que zsh
também define $status
compatibilidade com csh
(além de $?
)).
rc
: o status de saída $status
também está, mas quando morto por um sinal, essa variável contém o nome do sinal (como sigterm
ou sigill+core
se um núcleo foi gerado) em vez de um número, que é mais uma prova do bom design desse shell .
es
. o status de saída não é uma variável. Se você se importa com isso, execute o comando como:
status = <={cmd}
que retornará um número sigterm
ou sigsegv+core
igual a rc
.
Talvez para a completude, devemos mencionar zsh
's $pipestatus
e bash
' s $PIPESTATUS
matrizes que contêm o status de saída dos componentes do último pipeline.
E também para completar, quando se trata de funções de shell e arquivos de origem, as funções padrão retornam com o status de saída do último comando executado, mas também podem definir um status de retorno explicitamente com o return
builtin. E vemos algumas diferenças aqui:
bash
e mksh
(desde R41, uma regressão ^ aparentemente alterada intencionalmente ) truncará o número (positivo ou negativo) para 8 bits. Assim, por exemplo, return 1234
será definido $?
como 210
, return -- -1
será definido $?
como 255.
zsh
e pdksh
(e derivadas que não sejam mksh
) permitem qualquer número inteiro decimal de 32 bits assinado (-2 31 a 2 31 -1) (e truncar o número para 32 bits ).
ash
e yash
permita qualquer número inteiro positivo de 0 a 2 31 -1 e retorne um erro para qualquer número desse valor.
ksh93
para return 0
a return 320
set $?
como é, mas para qualquer outra coisa, truncado para 8 bits. Cuidado, como já mencionado, que retornar um número entre 256 e 320 pode causar o ksh
suicídio ao sair.
rc
e es
permitir retornar qualquer coisa par.
Observe também que alguns shells também usam valores especiais de $?
/ $status
para relatar algumas condições de erro que não são o status de saída de um processo, como 127
ou 126
para comando não encontrado ou não executável (ou erro de sintaxe em um arquivo de origem) ...
killall myScript
obras, portanto, o retorno do killall (e não do script!) é 0. Você pode colocar umkill -x $$
[x sendo o número do sinal e $$ geralmente expandido pelo shell para o PID do script (funciona em sh, bash, ...)] dentro do script e teste o que era seu núcleo de saída.