GNU/Linux >> Tutoriales Linux >  >> Linux

¿Código de salida predeterminado cuando finaliza el proceso?

Cuando se elimina 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 señales inmanejables como SIGKILL? ?

Por lo que puedo decir, matar un proceso con SIGINT probablemente resulte en el código de salida 130 , pero ¿varí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

Respuesta aceptada:

Los procesos pueden llamar al _exit() llamada al sistema (en Linux, consulte también exit_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 usa waitid() o controlador en SIGCHLD en el padre para recuperar ese código, aunque no en Linux).

El padre normalmente hará wait() o waitpid() para obtener el estado de su hijo como un número entero (aunque waitid() también se puede usar una semántica algo diferente).

En Linux y la mayoría de Unices, si el proceso terminó normalmente, los bits 8 a 15 de ese estado número contendrá el código de salida como se pasa a 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 descargó un núcleo.

perl 's $? por ejemplo, contiene ese número establecido por waitpid() :

$ perl -e 'system q(kill $$); printf "%04xn", $?'
000f # killed by signal 15
$ perl -e 'system q(kill -ILL $$); printf "%04xn", $?'
0084 # killed by signal 4 and core dumped
$ perl -e 'system q(exit $((0xabc))); printf "%04xn", $?'
bc00 # terminated normally, 0xbc the lowest 8 bits of the status

Los shells tipo Bourne también hacen que el estado de salida del último comando de ejecución sea su propio $? variable. Sin embargo, no contiene directamente el número devuelto por waitpid() , pero una transformación en él, y es diferente entre 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 pasado a exit() ) 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 a 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 de $? contendrá el número de señal. Pero, donde n es el número de la señal,

  • en ash, zsh, pdksh, bash, el shell Bourne, $? es 128 + n . Lo que eso significa es que en esos shells, si obtienes un $? de 129 , no sabes si es porque el proceso salió con exit(129) o si fue eliminado por la señal 1 (HUP en la mayoría de los sistemas). Pero la razón es que los shells, cuando salen por sí mismos, por defecto devuelven el estado de salida del último comando que salió. Asegurándose de que $? nunca es mayor a 255, eso permite tener un estado de salida consistente:

    $ bash -c 'sh -c "kill $$"; printf "%xn" "$?"'
    bash: line 1: 16720 Terminated              sh -c "kill $$"
    8f # 128 + 15
    $ bash -c 'sh -c "kill $$"; exit'; printf '%xn' "$?"
    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 , $? es 256 + n . Eso significa que a partir de un valor de $? puede diferenciar entre un proceso eliminado y no eliminado. Versiones más recientes de ksh , al salir, si $? era mayor que 255, se suicida 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 que ksh generará un volcado de núcleo adicional (potencialmente sobrescribiendo el otro) si el proceso fue detenido por una señal de generación de núcleo:

    $ ksh -c 'sh -c "kill $$"; printf "%xn" "$?"'
    ksh: 16828: Terminated
    10f # 256 + 15
    $ ksh -c 'sh -c "kill -ILL $$"; exit'; printf '%xn' "$?"
    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.
    

    Donde incluso podrías decir que hay un error es que ksh93 se suicida incluso si $? proviene de un return 257 hecho por una función:

    $ 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 ofrece un compromiso. Devuelve 256 + 128 + n . Eso significa que también podemos diferenciar entre un proceso muerto y uno que terminó correctamente. Y al salir, informará 128 + n sin tener que suicidarse y los efectos secundarios que puede tener.

    $ yash -c 'sh -c "kill $$"; printf "%xn" "$?"'
    18f # 256 + 128 + 15
    $ yash -c 'sh -c "kill $$"; exit'; printf '%xn' "$?"
    8f  # that's from a exit(143), yash was not killed
    

Para obtener la señal del valor de $? , la forma portátil es usar kill -l :

$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM

(para portabilidad, nunca debe usar números de señal, solo nombres de señal)

Relacionado:¿Copias de seguridad a nivel de byte versus a nivel de archivo?

En los frentes no Bourne:

  • csh /tcsh y fish igual que el shell de Bourne excepto que el estado está en $status en lugar de $? (tenga en cuenta que zsh también establece $status para compatibilidad con csh (además de $? )).
  • rc :el estado de salida está en $status también, pero cuando es eliminada por una señal, esa variable contiene el nombre de la señal (como sigterm o sigill+core si se generó un núcleo) en lugar de un número, lo cual es una prueba más del buen diseño de esa carcasa.
  • es . el estado de salida no es una variable. Si te importa, ejecuta el comando como:

    status = <={cmd}
    

    que devolverá un número o sigterm o sigsegv+core como en rc .

Tal vez para completar, deberíamos mencionar zsh 's $pipestatus y bash 's $PIPESTATUS matrices que contienen el estado de salida de los componentes de la última canalización.

Y también para completar, cuando se trata de funciones de shell y archivos de origen, las funciones predeterminadas regresan con el estado de salida de la última ejecución del comando, pero también pueden establecer un estado de retorno explícitamente con return incorporado. Y vemos algunas diferencias aquí:

  • bash y mksh (desde R41, una regresión^Wcambio aparentemente introducido intencionalmente) truncará el número (positivo o negativo) a 8 bits. Entonces, por ejemplo, return 1234 establecerá $? a 210 , return -- -1 establecerá $? a 255.
  • zsh y pdksh (y derivados distintos de mksh ) permite cualquier entero decimal de 32 bits con signo (-2 a 2-1) (y trunca el número a 32 bits).
  • ash y yash permite cualquier número entero positivo de 0 a 2-1 y devuelve un error para cualquier número fuera de eso.
  • ksh93 para return 0 para return 320 establecer $? como está, pero para cualquier otra cosa, truncar a 8 bits. Tenga cuidado, como ya se mencionó, de devolver un número entre 256 y 320 podría causar ksh suicidarse al salir.
  • rc y es permite devolver cualquier cosa, incluso listas.
Relacionado:arduino:¿gcode requiere un código de respuesta del intérprete?

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, como 127 o 126 para comando no encontrado o no ejecutable (o error de sintaxis en un archivo fuente)…


Linux
  1. ¿Nuevo proceso principal cuando muere el proceso principal?

  2. ¿Cómo buscar códigos de salida para aplicaciones?

  3. ¿Por qué se bifurca el mecanismo de creación de procesos predeterminado?

  4. ¿Qué código de error devuelve un proceso que falla en el segmento?

  5. Bash Prompt con el último código de salida

¿Cuándo se convirtió `relatime` en el valor predeterminado?

¿Qué son los códigos de salida de Bash en Linux?

Cuando la afirmación () falla, ¿cuál es el código de salida del programa?

¿Puede exit() fallar al terminar el proceso?

¿Cómo obtener el código de salida del proceso generado en el script de shell esperado?

¿Es posible aplicar un determinado código de salida al usar kill para detener un proceso?