Esistono codici di stato di uscita standard in Linux?

Si considera che un processo sia stato completato correttamente in Linux se il suo stato di uscita era 0.

Ho visto che gli errori di segmentazione spesso determinano uno stato di uscita di 11, anche se non so se si tratta semplicemente della convenzione in cui lavoro (le app che hanno avuto esito negativo sono state tutte interne) o di uno standard.

Esistono codici di uscita standard per i processi in Linux?

8 bit del codice di ritorno e 8 bit del numero del segnale di uccisione sono mescolati in un singolo valore sul ritorno da wait(2) & co. .

 #include  #include  #include  #include  #include  #include  int main() { int status; pid_t child = fork(); if (child <= 0) exit(42); waitpid(child, &status, 0); if (WIFEXITED(status)) printf("first child exited with %u\n", WEXITSTATUS(status)); /* prints: "first child exited with 42" */ child = fork(); if (child <= 0) kill(getpid(), SIGSEGV); waitpid(child, &status, 0); if (WIFSIGNALED(status)) printf("second child died with %u\n", WTERMSIG(status)); /* prints: "second child died with 11" */ } 

Come stai determinando lo stato di uscita? Tradizionalmente, la shell memorizza solo un codice di ritorno a 8 bit, ma imposta il bit alto se il processo è stato terminato in modo anomalo.

 $ sh -c 'exit 42';  echo $?
 42
 $ sh -c 'kill -SEGV $$';  echo $?
 Difetto di segmentazione
 139
 $ espr 139 - 128
 11

Se stai vedendo qualcosa di diverso da questo, allora il programma probabilmente ha un gestore di segnale SIGSEGV che poi chiama normalmente exit , quindi in realtà non viene ucciso dal segnale. (I programmi possono scegliere di gestire qualsiasi segnale oltre a SIGKILL e SIGSTOP .)

Parte 1: Guida avanzata di Bash Scripting

Come sempre, la Advanced Bash Scripting Guide ha ottime informazioni : (Questo è stato collegato in un’altra risposta, ma a un URL non canonico).

1: Catchall per errori generali
2: Uso improprio dei comandi incorporati nella shell (in base alla documentazione di Bash)
126: comando invocato non può essere eseguito
127: “comando non trovato”
128: argomento non valido per uscire
128 + n: segnale di errore fatale “n”
255: Esce dallo stato fuori intervallo (l’uscita richiede solo argomenti interi nell’intervallo 0 – 255)

Parte 2: sysexits.h

L’ABSG fa riferimento a sysexits.h .

Su Linux:

 $ find /usr -name sysexits.h /usr/include/sysexits.h $ cat /usr/include/sysexits.h /* * Copyright (c) 1987, 1993 * The Regents of the University of California. All rights reserved. (A whole bunch of text left out.) #define EX_OK 0 /* successful termination */ #define EX__BASE 64 /* base value for error messages */ #define EX_USAGE 64 /* command line usage error */ #define EX_DATAERR 65 /* data format error */ #define EX_NOINPUT 66 /* cannot open input */ #define EX_NOUSER 67 /* addressee unknown */ #define EX_NOHOST 68 /* host name unknown */ #define EX_UNAVAILABLE 69 /* service unavailable */ #define EX_SOFTWARE 70 /* internal software error */ #define EX_OSERR 71 /* system error (eg, can't fork) */ #define EX_OSFILE 72 /* critical OS file missing */ #define EX_CANTCREAT 73 /* can't create (user) output file */ #define EX_IOERR 74 /* input/output error */ #define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ #define EX_PROTOCOL 76 /* remote error in protocol */ #define EX_NOPERM 77 /* permission denied */ #define EX_CONFIG 78 /* configuration error */ #define EX__MAX 78 /* maximum listed value */ 

‘1’ >>> Catchall per errori generali

‘2’ >>> Uso improprio dei builtin della shell (secondo la documentazione di Bash)

‘126’ >>> Il comando invocato non può essere eseguito

‘127’ >>> “comando non trovato”

‘128’ >>> Argomento non valido per uscire

‘128 + n’ >>> Segnale di errore fatale “n”

‘130’ >>> Script terminato da Control-C

‘255’ >>> Esce dallo stato fuori intervallo

Questo è per bash. Tuttavia, per altre applicazioni, esistono diversi codici di uscita.

Nessuna delle risposte precedenti descrive correttamente lo stato di uscita 2. Contrariamente a quanto affermano, lo stato 2 è quello che le utilità della riga di comando effettivamente restituiscono quando vengono chiamate in modo errato. (Sì, una risposta può avere nove anni, avere centinaia di voti e comunque sbagliare).

Ecco la convenzione di stato di uscita reale, di vecchia data per la terminazione normale, ovvero non per segnale:

  • Stato di uscita 0: successo
  • Stato di uscita 1: “errore”, come definito dal programma
  • Stato di uscita 2: errore di utilizzo della riga di comando

Ad esempio, diff restituisce 0 se i file che confronta sono identici e 1 se differiscono. Con la convenzione di vecchia data, i programmi unix restituiscono lo stato di uscita 2 quando vengono chiamati in modo errato (opzioni sconosciute, numero errato di argomenti, ecc.) Ad esempio, diff -N , grep -Y o diff abc comporteranno tutti $? essere impostato su 2. Questa è ed è stata la pratica sin dagli albori di Unix negli anni ’70.

La risposta accettata spiega cosa succede quando un comando viene terminato da un segnale. In breve, la terminazione dovuta a un segnale non rilevato genera lo stato di uscita 128+[ . Ad esempio, la terminazione di SIGINT ( segnale 2 ) provoca lo stato di uscita 130.

Gli appunti

  1. Diverse risposte definiscono lo stato di uscita 2 come “Uso improprio dei buildin di bash”. Questo si applica solo quando bash (o uno script di bash) viene chiuso con lo stato 2. Consideralo un caso particolare di errore di utilizzo errato.

  2. In sysexits.h , menzionato nella risposta più popolare , lo stato di uscita EX_USAGE (“errore di utilizzo della riga di comando”) è definito come 64. Ma ciò non riflette la realtà: non sono a conoscenza di alcuna utilità Unix comune che restituisce 64 in modo errato invocazione (esempi benvenuti). Un’attenta lettura del codice sorgente rivela che sysexits.h è un’aspirazione, piuttosto che un riflesso del vero utilizzo:

      * This include file attempts to categorize possible error * exit statuses for system programs, notably delivermail * and the Berkeley network. * Error numbers begin at EX__BASE [64] to reduce the possibility of * clashing with other exit statuses that random programs may * already return. 

    In altre parole, queste definizioni non riflettono la pratica comune in quel momento (1993) ma erano intenzionalmente incompatibili con esso. Più è il peccato.

Non ci sono codici di uscita standard, a parte 0 significa successo. Non zero non significa necessariamente fallimento.

stdlib.h definisce EXIT_FAILURE come 1 e EXIT_SUCCESS come 0, ma questo è tutto.

L’11 su segfault è interessante, poiché 11 è il numero di segnale che il kernel usa per uccidere il processo nel caso di un segfault. C’è probabilmente un meccanismo, nel kernel o nella shell, che lo traduce nel codice di uscita.

sysexits.h ha una lista di codici di uscita standard. Sembra risalire almeno al 1993 e alcuni grandi progetti come Postfix lo usano, quindi immagino che sia la strada da percorrere.

Dalla pagina man di OpenBSD:

Secondo lo stile (9), non è consigliabile chiamare exit (3) con valori arbitrari per indicare una condizione di errore al termine di un programma. Invece, dovrebbero essere usati i codici di uscita predefiniti da sysexits, quindi il chiamante del processo può ottenere una stima approssimativa della class di errore senza cercare il codice sorgente.

Per una prima approssimazione, 0 è il successo, diverso da zero è il fallimento, con 1 è un errore generale e qualsiasi cosa più grande di uno è un errore specifico. A parte le banali eccezioni di false e test, che sono entrambi progettati per dare 1 per il successo, ci sono alcune altre eccezioni che ho trovato.

Più realisticamente, 0 significa successo o forse fallimento, 1 significa fallimento generale o forse successo, 2 significa errore generale se 1 e 0 sono entrambi utilizzati per il successo, ma forse anche il successo.

Il comando diff restituisce 0 se i file confrontati sono identici, 1 se differiscono e 2 se i binari sono diversi. 2 significa anche fallimento. Il comando less fornisce 1 per l’errore, a meno che tu non fornisca un argomento, nel qual caso, esce 0 nonostante non sia riuscito.

Più comandi e il comando ortografico danno 1 per errore, a meno che l’errore non sia il risultato di un permesso negato, di un file inesistente o di un tentativo di leggere una directory. In nessuno di questi casi, escono 0 nonostante non ce l’abbiano.

Quindi il comando expr fornisce 1 per il successo a meno che l’output non sia la stringa vuota o zero, nel qual caso, 0 è il successo. 2 e 3 sono guasti.

Poi ci sono casi in cui il successo o il fallimento sono ambigui. Quando grep non riesce a trovare un pattern, esce 1, ma esce 2 per un vero errore (come il permesso negato). Klist esce anche da 1 quando non riesce a trovare un ticket, anche se questo non è più un errore rispetto a quando grep non trova uno schema, o quando si trova una directory vuota.

Quindi, sfortunatamente, i poteri unix sembrano non applicare alcun insieme logico di regole, anche su eseguibili molto comunemente usati.

I programmi restituiscono un codice di uscita a 16 bit. Se il programma è stato ucciso con un segnale, il byte di ordine superiore contiene il segnale utilizzato, altrimenti il ​​byte di ordine inferiore è lo stato di uscita restituito dal programmatore.

Come viene assegnato il codice di uscita alla variabile di stato $? è quindi fino alla shell. Bash mantiene i 7 bit più bassi dello stato e quindi usa 128 + (segnale nr) per indicare un segnale.

L’unica convenzione “standard” per i programmi è 0 per il successo, non zero per l’errore. Un’altra convenzione utilizzata è restituire errno in caso di errore.

I codici di uscita standard di Unix sono definiti da sysexits.h, come menzionato da un altro poster. Gli stessi codici di uscita sono usati da librerie portatili come Poco – ecco un elenco di loro:

http://pocoproject.org/docs/Poco.Util.Application.html#16218

Un segnale 11 è un segnale SIGSEGV (violazione del segmento), che è diverso da un codice di ritorno. Questo segnale è generato dal kernel in risposta a un accesso errato alla pagina, che causa la chiusura del programma. Un elenco di segnali può essere trovato nella pagina man di segnale (eseguire “segnale uomo”).

Quando Linux restituisce 0, significa successo. Qualsiasi altra cosa significa fallimento, ogni programma ha i suoi codici di uscita, quindi sarebbe stato abbastanza lungo elencarli tutti …!

Circa il codice di errore 11, è in effetti il ​​numero di errore di segmentazione, per lo più il che significa che il programma ha effettuato l’accesso a una posizione di memoria che non è stata assegnata.