Quali sono i valori minimo e massimo dei codici di uscita in Linux?


40

Quali sono i valori minimo e massimo dei seguenti codici di uscita in Linux:

  1. Il codice di uscita restituito da un eseguibile binario (ad esempio: un programma C).
  2. Il codice di uscita restituito da uno script bash (durante la chiamata exit).
  3. Il codice di uscita restituito da una funzione (durante la chiamata return). Penso che questo sia tra 0e 255.

Per la parte 3, intendi tornare da una funzione shell ? Ciò può dipendere dalla shell, ma noto che il manuale di Bash dice "Gli stati di uscita sono compresi tra 0 e 255 " e "Anche gli stati di uscita dai comandi incorporati della shell e i comandi composti sono limitati a questo intervallo " return.
Toby Speight,

Correlato (contiene le risposte alla maggior parte delle domande): codice di uscita predefinito al termine del processo?
Stéphane Chazelas,

@TobySpeight, questa è una limitazione della bashshell. Alcune altre shell come zshpossono restituire qualsiasi valore a 32 bit con segno come per exit. Ad alcuni piace rco espuò restituire dati di qualsiasi tipo supportato (scalare o elencare). Vedi le domande e risposte collegate per i dettagli.
Stéphane Chazelas,

Risposte:


74

Il numero passato alla chiamata _exit()/ exit_group()system (a volte indicato come codice di uscita per evitare l'ambiguità con lo stato di uscita che si riferisce anche a una codifica del codice di uscita o del numero del segnale e informazioni aggiuntive a seconda che il processo sia stato terminato o chiuso normalmente ) è di tipo int, quindi su sistemi simili a Unix come Linux, in genere un numero intero a 32 bit con valori compresi tra -2147483648 (-2 31 ) e 2147483647 (2 31 -1).

Tuttavia, su tutti i sistemi, quando il processo padre (o la subreaper bambino o initse il genitore è morto) utilizza i wait(), waitpid(), wait3(), wait4()chiamate di sistema per recuperarla, solo gli ultimi 8 bit di esso sono disponibili (valori da 0 a 255 (2 8 - 1)).

Quando si utilizza l' waitid()API (o un gestore del segnale su SIGCHLD), sulla maggior parte dei sistemi (e come POSIX ora richiede più chiaramente nell'edizione 2016 dello standard (vedere le _exit()specifiche )), è disponibile il numero completo (nel si_statuscampo della struttura restituita ). Questo non è ancora il caso su Linux, che comunque tronca il numero a 8 bit con l' waitid()API, anche se è probabile che cambi in futuro.

In generale, si desidera utilizzare solo i valori da 0 (che in genere significano successo) a 125, poiché molte shell usano valori superiori a 128 nella loro $?rappresentazione dello stato di uscita per codificare il numero di segnale di un processo che viene ucciso e 126 e 127 per speciali condizioni.

Potresti voler usare 126 a 255 exit()per significare la stessa cosa che fanno per la shell $?(come quando fa uno script ret=$?; ...; exit "$ret"). L'uso di valori al di fuori di 0 -> 255 non è generalmente utile. Generalmente lo faresti solo se sai che il genitore utilizzerà l' waitid()API su sistemi che non si troncano e hai bisogno dell'intervallo di valori a 32 bit. Nota che se fai un exit(2048)esempio, questo sarà visto come un successo dai genitori usando il tradizionalewait*() API .

Maggiori informazioni su:

Speriamo che le domande e risposte rispondano alla maggior parte delle altre domande e chiariscano cosa si intende per stato di uscita . Aggiungerò alcune altre cose:

Un processo non può terminare a meno che non venga ucciso o non chiami le chiamate _exit()/ exit_group()system. Quando torni da main()dentroC , libc chiama quella chiamata di sistema con il valore restituito.

La maggior parte delle lingue ha una exit()funzione che avvolge quella chiamata di sistema e il valore che assumono, se ne viene generalmente passato uno qualsiasi alla chiamata di sistema. (nota che quelli generalmente fanno più cose come il clean-up fatto dalla exit()funzione di C che scarica i buffer dello stdio, esegue i atexit()ganci ...)

Questo è il caso di almeno:

$ strace -e exit_group awk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ strace -e exit_group mawk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ strace -e exit_group busybox awk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ echo | strace -e exit_group sed 'Q1234'
exit_group(1234)                        = ?
$ strace -e exit_group perl -e 'exit(1234)'
exit_group(1234)                        = ?
$ strace -e exit_group python -c 'exit(1234)'
exit_group(1234)                        = ?
$ strace -e exit_group expect -c 'exit 1234'
exit_group(1234)                        = ?
$ strace -e exit_group php -r 'exit(1234);'
exit_group(1234)                        = ?
$ strace -e exit_group zsh -c 'exit 1234'
exit_group(1234)

Di tanto in tanto vedi alcuni che si lamentano quando usi un valore esterno a 0-255:

$ echo 'm4exit(1234)' | strace -e exit_group m4
m4:stdin:1: exit status out of range: `1234'
exit_group(1)                           = ?

Alcune shell si lamentano quando si utilizza un valore negativo:

$ strace -e exit_group dash -c 'exit -1234'
dash: 1: exit: Illegal number: -1234
exit_group(2)                           = ?
$ strace -e exit_group yash -c 'exit -- -1234'
exit: `-1234' is not a valid integer
exit_group(2)                           = ?

POSIX lascia il comportamento indefinito se il valore passato al exitbuiltin speciale è esterno a 0-> 255.

Alcune shell mostrano alcuni comportamenti imprevisti se lo fai:

  • bash(e mkshnon pdkshsu cui si basa) si assume il compito di troncare il valore a 8 bit:

    $ strace -e exit_group bash -c 'exit 1234'
    exit_group(210)                         = ?
    

    Quindi in quelle shell, se vuoi uscire con un valore esterno a 0-255, devi fare qualcosa del tipo:

    exec zsh -c 'exit -- -12345'
    exec perl -e 'exit(-12345)'
    

    Cioè eseguire un altro comando nello stesso processo che può chiamare la chiamata di sistema con il valore desiderato.

  • come menzionato in quell'altra ksh93domanda e risposta , ha il comportamento più strano per i valori di uscita da 257 a 256 + max_signal_number dove invece di chiamare exit_group()si uccide con il segnale corrispondente¹.

    $ ksh -c 'exit "$((256 + $(kill -l STOP)))"'
    zsh: suspended (signal)  ksh -c 'exit "$((256 + $(kill -l STOP)))"'
    

    e altrimenti tronca il numero come bash/ mksh.


¹ Questo probabilmente cambierà nella prossima versione. Ora che lo sviluppo di ksh93è stato assunto come uno sforzo della comunità al di fuori di AT&T, quel comportamento, sebbene incoraggiato in qualche modo da POSIX, è stato ripristinato


2
Sai se c'è qualche discussione sull'implementazione del codice di uscita completo si_statusper Linux?
Ruslan,

2
@Ruslan, non più che l' austingroupbugs.net / view.php?id=594#c1318 (da Eric Blake (RedHat)) al link che ho dato
Stéphane Chazelas il

1
"è di tipo int, quindi un numero intero a 32 bit". Linux garantisce davvero che un int sarà sempre a 32 bit? Anche quando si esegue su alcuni di quei microcontrollori piccoli? Questo mi sembra davvero strano. POSIX certamente no.
Voo,

@Voo, quei piccoli microcontrollori non possono eseguire Linux. Sebbene C richieda intalmeno 16 bit, POSIX più o meno richiede almeno 32 bit e gli ambienti di programmazione devono avere un uint32_t . Non so se Linux supporti qualsiasi ambiente di programmazione in cui gli ints siano tutt'altro che 32 bit, non ne ho mai incontrato nessuno.
Stéphane Chazelas,

1
Su un sistema operativo comliant POSIX, è possibile ottenere il codice di uscita a 32 bit completo nella versione recente del Bourne Shell, vedere: schillix.sourceforge.net/man/man1/bosh.1.html
Schily

12

Il minimo è 0, ed è considerato il valore di successo. Tutti gli altri sono fallimenti. Il massimo è 255anche noto come -1.

Queste regole si applicano sia agli script che ad altri eseguibili, nonché alle funzioni della shell.

Valori più grandi risultano in modulo 256.


2
Per essere precisi, in alcune shell tipo Bourne (ma non basho in altre più comunemente usate) il codice di uscita passato all'integrato nonexit viene trattato come modulo-256 e causa invece un errore. (Ad esempio, il comune in realtà non è un equivalente portatile nella maggior parte delle shell). E se a livello C è equivalente è un dettaglio che è di fatto certo funzionante, ma si basa su comportamenti definiti dall'implementazione (anche se questo non è un problema sui sistemi moderni che probabilmente userete in pratica). exit -1exit 255exit(-1)exit(255)
mtraceur,

Da quello che so, solo ksh93 limita il exit(1)parametro a 8 bit.
schily,

6

Sembra così semplice, ma oh i guai.

Il linguaggio C (e in seguito il fatto che la maggior parte delle altre lingue direttamente o indirettamente) richiede che il ritorno mainsia equivalente alla chiamata exitcon lo stesso argomento del valore restituito. Questo è un numero intero (il tipo di ritorno è molto chiaro int), quindi in linea di principio la gamma sarebbe INT_MINa INT_MAX.

Tuttavia, POSIX afferma che solo gli 8 bit più bassi passati a exitdevono essere resi disponibili per un processo parent in attesa, letteralmente come se fosse "status & 0xFF" .
Quindi, in pratica, il codice di uscita è un numero intero (ancora con segno) di cui sono impostati solo gli 8 bit più bassi.

Il minimo sarà quindi -128 e il massimo 127 . Aspetta, non è vero. Sarà da 0 a 255.

Ma ahimè, ovviamente non può essere così semplice . In pratica, Linux (o meglio bash) lo fa diversamente . L'intervallo valido di codici di ritorno è compreso tra 0 e 255 (ovvero non firmato).

Per essere al sicuro in termini di evitare confusione, è probabilmente una buona idea presumere che i codici di ritorno non siano firmati e trasmettere tutto ciò da cui si ottiene indietro waita unsigned. In questo modo è coerente con ciò che vedi in una shell. Poiché i bit più in alto (incluso quello più significativo) vengono cancellati, non è nemmeno "sbagliato" perché, sebbene tecnicamente firmati, i valori effettivi sono sempre senza segno (poiché il bit di segno non viene mai impostato).
Aiuta anche a evitare l'errore comune di confrontare un codice di uscita -1, che per qualche strana ragione non sembra mai apparire anche quando un programma esce -1(beh, indovina perché!).

Informazioni sul tuo ultimo punto, ritorno da una funzione, se questa funzione sembra essere main, quindi vedi sopra. Altrimenti, dipende dal tipo di ritorno della funzione, in linea di principio potrebbe essere qualsiasi cosa (incluso void).


Hai avuto ragione prima del 1989, quando waitid()è stato introdotto.
schily,

@schily: non sei sicuro di cosa intendi? waitid()fa esattamente la stessa cosa, in modo leggermente diverso. Aspetta un particolare id o qualsiasi thread e scrive i risultati nella struttura puntata siginfo_tdove si si_statustrova int(quindi ... firmato , lo stesso). Tuttavia, exit()passa solo gli 8 bit più bassi, quindi ... assolutamente la stessa cosa sotto il cofano.
Damon,

exit()passa tutti i 32 bit del parametro al kernel e waitid()restituisce tutti i 32 bit dal codice di uscita. Forse hai controllato su Linux dove nessuno si preoccupa di correggere i bug. Se non mi credi, controlla su un sistema operativo POSIX conforme ...
schily

@schily: Se questo è vero (non penso che lo sia, ma comunque), allora Linux è rotto . Si prega di leggere la specifica POSIX collegata alla risposta exit, in particolare la seconda riga in "Descrizione" che indica: "sebbene solo gli 8 bit meno significativi (ovvero stato e 0377) siano disponibili per un processo parent in attesa " . Ecco come funziona un'implementazione conforme: 8 bit più in basso, non 32. Hai un riferimento per 32 bit che vengono passati?
Damon,

Pensavo di aver detto che Linux è rotto. Ancora peggio: le persone del kernel Linux si rifiutano di correggere i bug. Se leggi lo standard POSIX, scoprirai che la versione del 1995 (SUSv1) spiega correttamente la funzione originariamente introdotta da SVr4 nel 1989 e che le versioni recenti (ad esempio SUSv7tc2) dello standard spiegano anche esplicitamente che waitid()e la siginfo_tstruttura passata al SIGCHLDgestore restituisce tutti i 32 bit dal exit()parametro.
schily,

2
  1. Il codice di uscita restituito da un eseguibile binario (ad esempio: un programma C).
  2. Il codice di uscita restituito da uno script bash (quando si chiama exit).

I codici di uscita da qualsiasi processo, che si tratti di un eseguibile binario, di uno script di shell o di qualsiasi altra cosa, vanno da 0 a 255. È possibile passare un valore maggiore a exit(), ma solo gli 8 bit inferiori dello stato sono resi disponibili a altri processi attraverso wait().

  1. Il codice di uscita restituito da una funzione (quando si chiama return). Penso che questo sia tra 0 e 255.

La funzione AC può essere dichiarata come restituzione di quasi tutti i tipi. I limiti del suo valore di ritorno sono determinati interamente da quel tipo: ad esempio, da -128 a 127 per una funzione che ritorna signed char, o da 0 a 4,2 miliardi per una funzione che ritorna unsigned int, o qualsiasi numero in virgola mobile fino a e incluso infper una funzione che ritorna double. E questo non conta i tipi non numerici, come void *o un struct...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.