Cuando se mata un proceso con una señal manejable como SIGINT
o SIGTERM
pero no maneja la señal, ¿cuál será el código de salida del proceso?
¿Qué pasa con las señales no manejables como SIGKILL
?
Por lo que puedo decir, matar un proceso con SIGINT
resultados probables en el código de salida 130
, pero ¿variaría eso según la implementación del kernel o shell?
$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130
No estoy seguro de cómo probaría las otras señales ...
$ ./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
fuente
fuente
killall myScript
trabajos, por lo tanto, el retorno del killall (¡y no del script!) es 0. Podría colocar unkill -x $$
[x como el número de señal, y $$ generalmente expandido por el shell al PID de ese script (funciona en sh, bash, ...)] dentro del script y luego pruebe cuál era su núcleo de salida.&
) Envíe la señal desde otro proceso de shell (en otro terminal), luego puede usarla$?
después de que myScript haya finalizado.Respuestas:
Los procesos pueden llamar a la llamada del
_exit()
sistema (en Linux, ver tambiénexit_group()
) con un argumento entero para informar un código de salida a su padre. Aunque es un número entero, solo los 8 bits menos significativos están disponibles para el padre (la excepción es cuando se usawaitid()
o maneja en SIGCHLD en el padre para recuperar ese código , aunque no en Linux).El padre generalmente hará un
wait()
owaitpid()
para obtener el estado de su hijo como un entero (aunque tambiénwaitid()
se puede usar una semántica algo diferente).En Linux y en la mayoría de los Unices, si el proceso finalizó normalmente, los bits 8 a 15 de ese número de estado contendrán el código de salida que se le pasó
exit()
. De lo contrario, los 7 bits menos significativos (0 a 6) contendrán el número de señal y el bit 7 se establecerá si se volcó un núcleo.perl
's,$?
por ejemplo, contiene ese número establecido porwaitpid()
:Los shells tipo Bourne también hacen que el estado de salida del último comando de ejecución en su propia
$?
variable. Sin embargo, no contiene directamente el número devuelto porwaitpid()
, sino una transformación, y es diferente entre los shells.Lo que es común entre todos los shells es que
$?
contiene los 8 bits más bajos del código de salida (el número pasadoexit()
) si el proceso terminó normalmente.Donde difiere es cuando el proceso termina con una señal. En todos los casos, y eso es requerido por POSIX, el número será mayor que 128. POSIX no especifica cuál puede ser el valor. Sin embargo, en la práctica, en todos los shells tipo Bourne que conozco, los 7 bits más bajos
$?
contendrán el número de señal. Pero, ¿dónden
está el número de señal?en ash, zsh, pdksh, bash, el shell Bourne,
$?
es128 + n
. Lo que eso significa es que en esos proyectiles, si obtienes uno$?
de129
, no sabes si es porque el proceso salióexit(129)
o si la señal lo mató1
(HUP
en la mayoría de los sistemas). Pero la razón es que los shells, cuando salen ellos mismos, por defecto devuelven el estado de salida del último comando salido. Al asegurarse de$?
que nunca sea mayor que 255, eso permite tener un estado de salida consistente:ksh93
,$?
Es256 + n
. Eso significa que a partir de un valor de$?
usted puede diferenciar entre un proceso muerto y no muerto. Las versiones más nuevas deksh
, al salir, si$?
eran superiores a 255, se suicidan con la misma señal para poder informar el mismo estado de salida a su padre. Si bien eso suena como una buena idea, eso significa queksh
generará un volcado de núcleo adicional (posiblemente sobrescribiendo el otro) si el proceso fue eliminado por una señal generadora de núcleo:Donde incluso podría decir que hay un error es que se
ksh93
suicida incluso si$?
proviene de una funciónreturn 257
realizada por:yash
.yash
ofrece un compromiso Vuelve256 + 128 + n
. Eso significa que también podemos diferenciar entre un proceso cancelado y uno que finalizó correctamente. Y al salir, informará128 + n
sin tener que suicidarse y los efectos secundarios que puede tener.Para obtener la señal del valor de
$?
, la forma portátil es usarkill -l
:(para portabilidad, nunca debe usar números de señal, solo nombres de señal)
En los frentes no Bourne:
csh
/tcsh
efish
igual que el shell Bourne, excepto que el estado está en$status
lugar de$?
(tenga en cuenta quezsh
también establece la$status
compatibilidad concsh
(además de$?
)).rc
: El estado de salida está en$status
también, pero cuando matado por una señal, dicha variable contiene el nombre de la señal (comosigterm
osigill+core
si se generó un núcleo) en lugar de un número, que es otra prueba del diseño bien de que shell .es
. El estado de salida no es una variable. Si te importa, ejecutas el comando como:que devolverá un número
sigterm
o mesigsegv+core
gusta enrc
.Tal vez para completar, deberíamos mencionar
zsh
las matrices 's$pipestatus
ybash
'$PIPESTATUS
que contienen el estado de salida de los componentes de la última tubería.Y también para completar, cuando se trata de funciones de shell y archivos de origen, las funciones por defecto regresan con el estado de salida del último comando ejecutado, pero también pueden establecer un estado de retorno explícitamente con el
return
incorporado. Y vemos algunas diferencias aquí:bash
ymksh
(desde R41, una regresión ^ Wchange aparentemente introducida intencionalmente ) truncará el número (positivo o negativo) a 8 bits. Entonces, por ejemplo,return 1234
se establecerá$?
en210
,return -- -1
se establecerá$?
en 255.zsh
ypdksh
(y derivados distintos demksh
) permiten cualquier entero decimal con signo de 32 bits (-2 31 a 2 31 -1) (y truncan el número a 32 bits).ash
yyash
permitir cualquier número entero positivo de 0 a 2 31 -1 y devolver un error para cualquier número de eso.ksh93
parareturn 0
alreturn 320
conjunto$?
como es, pero para cualquier otra cosa, truncado a 8 bits. Tenga en cuenta, como ya se mencionó, que devolver un número entre 256 y 320 podría causar laksh
muerte al salir.rc
yes
permitir devolver cualquier cosa, incluso listas.También tenga en cuenta que algunos shells también usan valores especiales de
$?
/$status
para informar algunas condiciones de error que no son el estado de salida de un proceso, como127
o126
para el comando no encontrado o no ejecutable (o error de sintaxis en un archivo de origen) ...fuente
an exit code to their parent
yto get the *status* of their child
. has agregado énfasis en el "estado". Esexit code
y*status*
lo mismo? Caso sí, ¿cuál es el origen de tener dos nombres? Caso no igual, ¿podría dar definición / referencia de estado?exit()
. El estado de salida : el número obtenido por elwaitpid()
cual incluye el código de salida, el número de señal y si hubo un núcleo volcado. Y el número que algunos shells ponen a disposición en una de sus variables especiales ($?
,$status
) que es una transformación del estado de salida de tal manera que contiene el código de salida en caso de que haya una terminación normal, pero también lleva información de señal si el proceso fue cancelado (a ese también se le llama generalmente estado de salida ). Todo eso se explica en mi respuesta.> 128
parte: "El estado de salida de un comando que terminó porque recibió una señal se informará como mayor que 128". pubs.opengroup.org/onlinepubs/9699919799/utilities/…[email protected]
(del 06/05/2015) oXref: news.gmane.org gmane.comp.standards.posix.austin.general:10726
Cuando sale un proceso, devuelve un valor entero al sistema operativo. En la mayoría de las variantes de Unix, este valor se toma en el módulo 256: se ignora todo menos los bits de orden inferior. El estado de un proceso hijo se devuelve a su padre a través de un entero de 16 bits en el que
El estado lo devuelve la
wait
llamada del sistema o uno de sus hermanos. POSIX no especifica la codificación exacta del estado de salida y el número de señal; solo proporcionaEstrictamente hablando, no hay código de salida cuando un proceso es eliminado por una señal: lo que sí hay es un estado de salida .
En un script de shell, el estado de salida de un comando se informa a través de la variable especial
$?
. Esta variable codifica el estado de salida de una manera ambigua:$?
es su estado de salida.$?
es 128 más el número de señal en la mayoría de los sistemas. POSIX solo exige que$?
sea mayor que 128 en este caso; ksh93 agrega 256 en lugar de 128. Nunca he visto una variante de Unix que hiciera otra cosa que agregar una constante al número de señal.Por lo tanto, en un script de shell no se puede determinar de manera concluyente si un comando fue eliminado por una señal o si salió con un código de estado superior a 128, excepto con ksh93. Es muy raro que los programas salgan con códigos de estado superiores a 128, en parte porque los programadores lo evitan debido a la
$?
ambigüedad.SIGINT es la señal 2 en la mayoría de las variantes de Unix, por lo tanto,
$?
es 128 + 2 = 130 para un proceso que fue eliminado por SIGINT. Verás 129 para SIGHUP, 137 para SIGKILL, etc.fuente
$?
es solo para conchas tipo Bourne. Consulte tambiényash
un comportamiento diferente (pero aún POSIX). También según POSIX + XSI (Unix), akill -2 "$pid"
enviará un SIGINT al proceso, pero el número de señal real puede no ser 2, entonces $? no necesariamente será 128 + 2 (o 256 + 2 o 384 + 2), aunquekill -l "$?"
regresaráINT
, por lo que recomendaría que la portabilidad no se refiera a los números en sí.Eso depende de tu caparazón. Desde la
bash(1)
página de manual, sección SHELL GRAMMAR , subsección Comandos simples :Como
SIGINT
en su sistema está la señal número 2, el valor de retorno es 130 cuando se ejecuta bajo Bash.fuente
signal(7)
página de manual.Parece ser el lugar adecuado para mencionar que SVr4 introdujo waitid () en 1989, pero ningún programa importante parece usarlo hasta ahora. waitid () permite recuperar los 32 bits completos del código de salida ().
Hace aproximadamente 2 meses, reescribí la parte de espera / control de trabajo de Bourne Shell para usar waitid () en lugar de waitpid (). Esto se hizo para eliminar la limitación que enmascara el código de salida con 0xFF.
La interfaz waitid () es mucho más limpia que las implementaciones anteriores wait (), excepto la llamada cwait () de UNOS desde 1980.
Puede interesarle leer la página de manual en:
http://schillix.sourceforge.net/man/man1/bosh.1.html
y revise la sección "Sustitución de parámetros" que se encuentra actualmente en la página 8.
Las nuevas variables .sh. * Se han introducido para la interfaz waitid (). Esta interfaz ya no tiene significados ambiguos para los números conocidos por $? y hacer la interfaz mucho más fácil.
Tenga en cuenta que debe tener un waitid () compatible con POSIX para poder usar esta función, por lo que Mac OS X y Linux actualmente no ofrecen esto, pero el waitid () se emula en la llamada waitpid (), así que en un Sin la plataforma POSIX, solo obtendrá 8 bits del código de salida.
En resumen: .sh.status es el código de salida numérico, .sh.code es el motivo de salida numérico.
Para una mejor portabilidad, existe: .sh.codename para la versión textual del motivo de salida, por ejemplo, "DUMPED" y .sh.termsig, el nombre único de la señal que finalizó el proceso.
Para un mejor uso, hay dos valores .sh.codename no relacionados con la salida: "NOEXEC" y "NOTFOUND" que se utilizan cuando no se puede iniciar un programa.
FreeBSD corrigió su error del kernel waitid () dentro de las 20 horas posteriores a mi informe, Linux aún no comenzó con su corrección. Espero que 26 años después de presentar esta característica que se encuentra en POSIX ahora, todos los sistemas operativos lo admitirán pronto.
fuente