Quando um processo é interrompido com um sinal manipulável como SIGINT
ou SIGTERM
mas não manipula o sinal, qual será o código de saída do processo?
E quanto a sinais que não podem ser manuseados SIGKILL
?
Pelo que posso dizer, matar um processo com SIGINT
resultados prováveis no código de saída 130
, mas isso varia de acordo com a implementação do kernel ou do shell?
$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130
Não sei como testaria os outros sinais ...
$ ./myScript &
$ killall myScript
$ echo $?
0 # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0 # same problem
kill
signals
exit
exit-status
Cory Klein
fonte
fonte
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.&
). Envie o sinal de outro processo shell (em outro terminal) e use-o$?
após o término do myScript.Respostas:
Os processos podem chamar a chamada do
_exit()
sistema (no Linux, consulte tambémexit_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 usawaitid()
ou manipula SIGCHLD no pai para recuperar esse código , embora não no Linux).O pai normalmente faz um
wait()
ouwaitpid()
para obter o status de seu filho como um número inteiro (embora tambémwaitid()
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 porwaitpid()
: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 porwaitpid()
, 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 paraexit()
) 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, onden
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$?
dos129
, você não sabe se é porque o processo foi encerrado comexit(129)
ou se ele foi morto pelo sinal1
(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: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 deksh
, 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 queksh
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:Onde você pode até dizer que há um bug é que se
ksh93
mata mesmo que$?
provenha dereturn 257
uma função:yash
.yash
oferece um compromisso. Retorna256 + 128 + n
. Isso significa que também podemos diferenciar entre um processo morto e um que terminou corretamente. E ao sair, será relatado128 + n
sem ter que se suicidar e os efeitos colaterais que pode ter.Para obter o sinal do valor de
$?
, a maneira portátil é usarkill -l
:(para portabilidade, você nunca deve usar números de sinal, apenas nomes de sinal)
Nas frentes não Bourne:
csh
/tcsh
e ofish
mesmo que o shell Bourne, exceto que o status está em$status
vez de$?
(observe quezsh
também define$status
compatibilidade comcsh
(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 (comosigterm
ousigill+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:que retornará um número
sigterm
ousigsegv+core
igual arc
.Talvez para a completude, devemos mencionar
zsh
's$pipestatus
ebash
' 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
emksh
(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$?
como210
,return -- -1
será definido$?
como 255.zsh
epdksh
(e derivadas que não sejammksh
) 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
eyash
permita qualquer número inteiro positivo de 0 a 2 31 -1 e retorne um erro para qualquer número desse valor.ksh93
parareturn 0
areturn 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 oksh
suicídio ao sair.rc
ees
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, como127
ou126
para comando não encontrado ou não executável (ou erro de sintaxe em um arquivo de origem) ...fonte
an exit code to their parent
eto get the *status* of their child
. você adicionou ênfase ao "status". Éexit code
e*status*
o mesmo? Caso sim, qual é a origem de ter dois nomes? Caso não seja o mesmo, você poderia dar definição / referência de status?exit()
. O status de saída : o número obtido pelowaitpid()
qual inclui o código de saída, número do sinal e se houve um core despejado. E o número que alguns shells disponibilizam em uma de suas variáveis especiais ($?
,$status
) que é uma transformação do status de saída de forma que contenha o código de saída no caso de uma terminação normal, mas também carrega informações de sinal se o processo foi interrompido (esse também é geralmente chamado de status de saída ). Tudo isso está explicado na minha resposta.> 128
parte: "O status de saída de um comando que terminou porque recebeu um sinal deve ser relatado como superior a 128". pubs.opengroup.org/onlinepubs/9699919799/utilities/…[email protected]
(de 06/05/2015) ouXref: news.gmane.org gmane.comp.standards.posix.austin.general:10726
Quando um processo sai, ele retorna um valor inteiro para o sistema operacional. Na maioria das variantes unix, esse valor é obtido no módulo 256: tudo, exceto os bits de ordem inferior, é ignorado. O status de um processo filho é retornado ao pai através de um número inteiro de 16 bits no qual
O status é retornado pela
wait
chamada do sistema ou por um de seus irmãos. O POSIX não especifica a codificação exata do status de saída e do número do sinal; apenas forneceA rigor, não há código de saída quando um processo é interrompido por um sinal: o que existe é um status de saída .
Em um script de shell, o status de saída de um comando é relatado por meio da variável especial
$?
. Essa variável codifica o status de saída de uma maneira ambígua:$?
é seu status de saída.$?
é 128 mais o número do sinal na maioria dos sistemas. O POSIX apenas exige que$?
seja maior que 128 neste caso; O ksh93 adiciona 256 em vez de 128. Nunca vi uma variante unix que fiz algo diferente de adicionar uma constante ao número do sinal.Portanto, em um script shell, você não pode dizer conclusivamente se um comando foi morto por um sinal ou saiu com um código de status maior que 128, exceto com ksh93. É muito raro os programas saírem com códigos de status maiores que 128, em parte porque os programadores evitam isso devido à
$?
ambiguidade.SIGINT é o sinal 2 na maioria das variantes unix, portanto,
$?
é 128 + 2 = 130 para um processo que foi eliminado pelo SIGINT. Você verá 129 para SIGHUP, 137 para SIGKILL etc.fonte
$?
é apenas para conchas do tipo Bourne. Veja tambémyash
para um comportamento diferente (mas ainda POSIX). Também de acordo com o POSIX + XSI (Unix), akill -2 "$pid"
enviará um SIGINT ao processo, mas o número real do sinal pode não ser 2, então $? não será necessariamente 128 + 2 (ou 256 + 2 ou 384 + 2), maskill -l "$?"
retornaráINT
, e é por isso que aconselho a portabilidade a não se referir aos números em si.Isso depende da sua concha. Na
bash(1)
página do manual, seção SHELL GRAMMAR , subseção Comandos Simples :Como
SIGINT
em seu sistema o sinal é o número 2, o valor de retorno é 130 quando é executado no Bash.fonte
signal(7)
página de manual.Parece ser o lugar certo para mencionar que o SVr4 introduziu waitid () em 1989, mas nenhum programa importante parece usá-lo até agora. waitid () permite recuperar os 32 bits completos do código exit ().
Há cerca de dois meses, reescrevi a parte de controle de espera / trabalho do Bourne Shell para usar waitid () em vez de waitpid (). Isso foi feito para remover a limitação que mascara o código de saída com 0xFF.
A interface waitid () é muito mais limpa que as implementações wait () anteriores, exceto a chamada cwait () do UNOS de 1980.
Você pode estar interessado em ler a página de manual em:
http://schillix.sourceforge.net/man/man1/bosh.1.html
e verifique a seção "Substituição de parâmetros" atualmente na página 8.
As novas variáveis .sh. * Foram introduzidas para a interface waitid (). Essa interface não possui mais significados ambíguos para os números conhecidos por $? e tornar a interface muito mais fácil.
Observe que você precisa de um waitid () compatível com POSIX para poder usar esse recurso; portanto, atualmente, o Mac OS X e Linux não oferecem isso, mas o waitid () é emulado na chamada waitpid (), e assim por diante. Na plataforma não-POSIX, você ainda obterá apenas 8 bits do código de saída.
Em resumo: .sh.status é o código de saída numérico, .sh.code é o motivo de saída numérica.
Para uma melhor portabilidade, existe: .sh.codename para a versão textual do motivo da saída, por exemplo, "DUMPED" e .sh.termsig, o nome original do sinal que encerrou o processo.
Para melhor uso, existem dois valores .sh.codename não relacionados à saída: "NOEXEC" e "NOTFOUND" que são usados quando um programa não pode ser iniciado.
O FreeBSD corrigiu seu bug waitid () kerlnel dentro de 20 horas após o meu relatório, o Linux ainda não começou com a correção. Espero que 26 anos após a introdução desse recurso que está no POSIX agora, todos os sistemas operacionais o suportem em breve.
fonte