GNU/Linux >> Linux Esercitazione >  >> Linux

Codice di uscita predefinito al termine del processo?

Quando un processo viene terminato con un segnale gestibile come SIGINT o SIGTERM ma non gestisce il segnale, quale sarà il codice di uscita del processo?

Che dire di segnali ingestibili come SIGKILL ?

Da quello che posso dire, uccidere un processo con SIGINT probabili risultati nel codice di uscita 130 , ma potrebbe variare in base all'implementazione del kernel o della shell?

$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130

Non sono sicuro di come testare gli altri segnali...

$ ./myScript &
$ killall myScript
$ echo $?
0  # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0  # same problem

Risposta accettata:

I processi possono chiamare _exit() chiamata di sistema (su Linux, vedere anche exit_group() ) con un argomento intero per segnalare un codice di uscita al genitore. Sebbene sia un numero intero, solo gli 8 bit meno significativi sono disponibili per il genitore (l'eccezione è quando si utilizza waitid() o gestore su SIGCHLD nel genitore per recuperare quel codice, anche se non su Linux).

Il genitore in genere esegue un wait() o waitpid() per ottenere lo stato del figlio come numero intero (sebbene waitid() con semantica un po' diversa può essere usata pure).

Su Linux e sulla maggior parte degli Unice, se il processo terminava normalmente, i bit da 8 a 15 di quello stato number conterrà il codice di uscita passato a exit() . In caso contrario, i 7 bit meno significativi (da 0 a 6) conterranno il numero del segnale e il bit 7 verrà impostato se è stato eseguito il dump di un core.

perl 's $? ad esempio contiene quel numero come impostato da 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

Le shell simili a Bourne creano anche lo stato di uscita dell'ultimo comando eseguito nel proprio $? variabile. Tuttavia, non contiene direttamente il numero restituito da waitpid() , ma una trasformazione su di esso, ed è diverso tra le shell.

Ciò che è comune a tutte le shell è che $? contiene gli 8 bit più bassi del codice di uscita (il numero passato a exit() ) se il processo è terminato normalmente.

Dove differisce è quando il processo viene terminato da un segnale. In tutti i casi, ed è richiesto da POSIX, il numero sarà maggiore di 128. POSIX non specifica quale può essere il valore. In pratica, però, in tutte le shell Bourne che conosco, i 7 bit più bassi di $? conterrà il numero del segnale. Ma, dove n è il numero del segnale,

  • in ash, zsh, pdksh, bash, la shell Bourne, $? è 128 + n . Ciò significa che in quelle shell, se ottieni un $? di 129 , non sai se è perché il processo è terminato con exit(129) o se è stato ucciso dal segnale 1 (HUP sulla maggior parte dei sistemi). Ma la logica è che le shell, quando escono da sole, per impostazione predefinita restituiscono lo stato di uscita dell'ultimo comando uscito. Assicurandoti $? non è mai maggiore di 255, che consente di avere uno stato di uscita coerente:

    $ 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 , $? è 256 + n . Ciò significa che da un valore di $? puoi distinguere tra un processo ucciso e non ucciso. Versioni più recenti di ksh , all'uscita, se $? era maggiore di 255, si uccide con lo stesso segnale per poter segnalare lo stesso stato di uscita al genitore. Anche se sembra una buona idea, significa che ksh genererà un core dump aggiuntivo (potenzialmente sovrascrivendo l'altro) se il processo è stato interrotto da un segnale di generazione del core:

    $ 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.
    

    Dove potresti anche dire che c'è un bug è che ksh93 si uccide anche se $? proviene da un return 257 fatto da una funzione:

    $ 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 offre un compromesso. Restituisce 256 + 128 + n . Ciò significa che possiamo anche distinguere tra un processo terminato e uno terminato correttamente. E all'uscita riporterà 128 + n senza doversi suicidare e gli effetti collaterali che può avere.

    $ 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
    

Per ottenere il segnale dal valore di $? , il modo portatile consiste nell'usare kill -l :

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

(per la portabilità, non dovresti mai usare numeri di segnale, solo nomi di segnali)

Correlati:backup a livello di byte e backup a livello di file?

Sui fronti non Bourne:

  • csh /tcsh e fish come la shell Bourne tranne per il fatto che lo stato è in $status invece di $? (nota che zsh imposta anche $status per compatibilità con csh (oltre a $? )).
  • rc :lo stato di uscita è in $status anche, ma quando viene uccisa da un segnale, quella variabile contiene il nome del segnale (come sigterm o sigill+core se è stato generato un core) invece di un numero, che è l'ennesima prova del buon design di quella shell.
  • es . lo stato di uscita non è una variabile. Se ti interessa, esegui il comando come:

    status = <={cmd}
    

    che restituirà un numero o sigterm o sigsegv+core come in rc .

Forse per completezza dovremmo citare zsh 's $pipestatus e bash 's $PIPESTATUS array che contengono lo stato di uscita dei componenti dell'ultima pipeline.

E anche per completezza, quando si tratta di funzioni di shell e file sorgente, per impostazione predefinita le funzioni ritornano con lo stato di uscita dell'ultimo comando eseguito, ma possono anche impostare uno stato di ritorno in modo esplicito con return incorporato. E vediamo alcune differenze qui:

  • bash e mksh (da R41, una regressione^Wchange apparentemente introdotta intenzionalmente) troncherà il numero (positivo o negativo) a 8 bit. Quindi, ad esempio, return 1234 imposterà $? a 210 , return -- -1 imposterà $? a 255.
  • zsh e pdksh (e derivati ​​diversi da mksh ) consente qualsiasi intero decimale a 32 bit con segno (da -2 a 2-1) (e tronca il numero a 32 bit).
  • ash e yash consentire qualsiasi numero intero positivo compreso tra 0 e 2-1 e restituire un errore per qualsiasi numero al di fuori di quello.
  • ksh93 per return 0 a return 320 impostare $? così com'è, ma per qualsiasi altra cosa, troncare a 8 bit. Attenzione come già accennato che restituire un numero compreso tra 256 e 320 potrebbe causare ksh uccidersi all'uscita.
  • rc e es consentire la restituzione di qualsiasi elenco anche.
Correlati:arduino – gcode richiede un codice di risposta dall'interprete?

Nota anche che alcune shell usano anche valori speciali di $? /$status per segnalare alcune condizioni di errore che non sono lo stato di uscita di un processo, come 127 o 126 per comando non trovato o non eseguibile (o errore di sintassi in un file sorgente)...


Linux
  1. Linux – Quando non dovrei uccidere -9 Un processo?

  2. Nuovo processo genitore quando il processo genitore muore?

  3. Quando è stato impostato "relatime" come predefinito?

  4. Cosa sono i codici di uscita Bash in Linux

  5. exit() può non riuscire a terminare il processo?

Come cercare i codici di uscita per le applicazioni?

Perché il meccanismo di creazione del processo predefinito è fork?

Quando assert() fallisce, qual è il codice di uscita del programma?

Bash Prompt con il codice dell'ultima uscita

Come ottenere il codice di uscita del processo generato nello script di shell atteso?

Cosa fare quando Ctrl + C non può terminare un processo?