Perché 0 è vero ma falso è 1 nella shell?

false; echo $? 

Quanto sopra uscirà 1 , che è in contraddizione con tutti gli altri linguaggi di programmazione che conosco.

Qualche ragione in questo?

È una convenzione, ma particolarmente utile quando ci pensi. In generale, se un programma ha successo, è tutto ciò che devi sapere. Se fallisce, tuttavia, potrebbe essere necessario conoscere tutti i tipi di informazioni sull’errore: perché è successo, come risolverlo, ecc. Avere zero significa “successo” e l’errore medio non zero consente di controllare abbastanza facilmente per il successo e analizza l’errore particolare per ulteriori dettagli, se lo desideri. Un sacco di API e framework hanno una convenzione simile – le funzioni che hanno successo restituiscono 0 e quelle che non riescono restituiscono un codice di errore che descrive il particolare caso di errore.

Bash è un linguaggio di programmazione (scripting), ma è anche una shell e un’interfaccia utente. Se 0 era un errore, il programma poteva presentare solo un tipo di errore.

Tuttavia in Bash, qualsiasi valore diverso da zero è un errore e potremmo utilizzare qualsiasi numero compreso tra 1-255 per rappresentare un errore. Ciò significa che possiamo avere molti diversi tipi di errori. 1 è un errore generale, 126 significa che un file non può essere eseguito, 127 significa ‘comando non trovato’, ecc. Ecco un elenco di codici di uscita riservati Bash che mostrano alcuni dei codici di uscita più comuni.

Esistono anche molti tipi di successo (lo stato di uscita è 0 ). Tuttavia, un successo ti consentirà di procedere al passaggio successivo: puoi ad esempio stampare i risultati su uno schermo o eseguire un comando, ecc.

Ci sono due problemi correlati qui.

Innanzitutto, la domanda dell’OP, perché 0 è vero ma falso è 1 nella shell? e il secondo, perché le applicazioni restituiscono 0 per il successo e non-zero per il fallimento?

Per rispondere alla domanda dell’OP dobbiamo capire la seconda domanda. Le numerose risposte a questo post hanno descritto che questa è una convenzione e hanno elencato alcune delle sottigliezze che questa convenzione offre. Alcune di queste sottigliezze sono riassunte di seguito.

Perché le applicazioni restituiscono 0 per il successo e non zero per il fallimento?

Il codice che richiama un’operazione deve conoscere due cose sullo stato di uscita dell’operazione. L’operazione è stata eseguita correttamente? [* 1] E se l’operazione non viene completata correttamente, perché l’operazione è stata chiusa senza successo? Qualsiasi valore può essere utilizzato per indicare il successo. Ma 0 è più conveniente di qualsiasi altro numero perché è portatile tra le piattaforms. Riassumendo la risposta di xibo a questa domanda il 16 agosto 2011:

Zero è indipendente dalla codifica.

Se volessimo memorizzare un (1) in una parola intera a 32 bit, la prima domanda sarebbe “parola big-endian o parola little-endian?”, Seguita da “quanto sono lunghi i byte che compongono una parola little-endian? “, mentre zero sarà sempre lo stesso.

Inoltre, ci si deve aspettare che alcune persone trasmettano errno a char o short ad un certo punto, o addirittura a fluttuare. (int) ((char) ENOLCK) non è ENOLCK quando char non è almeno lungo 8 bit (le macchine con caratteri ASCII a 7 bit sono supportate da UNIX), mentre (int) ((char) 0) è 0 indipendente dal dettagli architettonici di char.

Una volta determinato che 0 sarà il valore di ritorno per il successo, allora ha senso usare qualsiasi valore diverso da zero per il fallimento. Ciò consente a molti codici di uscita di rispondere alla domanda perché l’operazione non è riuscita.

Perché 0 è vero ma falso è 1 nella shell?

Uno degli usi fondamentali delle shell è quello di automatizzare i processi mediante la loro creazione di script. Di solito questo significa invocare un’operazione e quindi fare qualcos’altro in modo condizionale in base allo stato di uscita dell’operazione. Philippe A. ha spiegato bene nella sua risposta a questo post

In bash e in shell unix in generale, i valori restituiti non sono booleani. Sono codici di uscita interi.

È necessario quindi interpretare lo stato di uscita di queste operazioni come valore booleano. Ha senso mappare uno stato di uscita con successo ( 0 ) su true e qualsiasi stato di uscita diverso da zero / errore su falso. Ciò consente l’esecuzione condizionale dei comandi della shell concatenata.

Ecco un esempio di mkdir deleteme && cd $_ && pwd . Poiché la shell interpreta 0 come vero, questo comando funziona in modo appropriato come previsto. Se la shell interpretasse 0 come falso, dovresti invertire lo stato di uscita interpretato per ogni operazione.

In breve, sarebbe privo di senso per la shell interpretare 0 come falso data la convenzione che le applicazioni restituiscono 0 per uno stato di uscita riuscito.


[* 1]: Sì, molte volte le operazioni devono restituire più di un semplice messaggio di successo, ma ciò va oltre lo scopo di questa discussione.

Vedi anche l’ Appendice E nella Guida avanzata di Bash-Scripting

È solo una convenzione che un codice di uscita 0 significa successo. EXIT_SUCCESS sarà 0 su quasi tutti i sistemi moderni.

MODIFICARE:

“perché sia ​​il test 0 che il test 1 restituiscono 0 (successo)?”

Questa è una domanda completamente diversa. La risposta è che passare un singolo argomento per test ha sempre esito positivo a meno che quell’argomento non sia la stringa nulla (“”). Vedi la documentazione di Open Group .

L’unico punto fondamentale che trovo importante da capire è questo. In bash e in shell unix in generale, i valori restituiti non sono booleani. Sono codici di uscita interi. Pertanto, è necessario valutarli in base alla convenzione dicendo che 0 significa successo e altri valori indicano un errore.

Con gli operatori test , [ ] o [[ ]] , le condizioni di bash vengono valutate come true in caso di un codice di uscita 0 (il risultato di / bin / true). Altrimenti valutano come falso.

Le stringhe sono valutate in modo diverso rispetto ai codici di uscita:

 if [ 0 ] ; then echo not null ; fi if [ $(echo 0) ] ; then echo not null ; fi if [ -z "" ] ; then echo null ; fi 

L’operatore aritmetico (( )) interpreta 1 e 0 come vero e falso. Ma quell’operatore non può essere utilizzato come sostituzione completa per il test , [ ] o [[ ]] . Ecco un esempio che mostra quando l’operatore aritmetico è utile:

 for (( counter = 0 ; counter < 10 ; counter ++ )) ; do if (( counter % 2 )) ; then echo "odd number $counter" ; fi done 

In genere i programmi restituiscono zero per il successo, non zero per il fallimento; false restituisce 1 perché è un valore non diverso conveniente, ma in genere qualsiasi valore diverso da zero indica un errore di qualche tipo e molti programmi restituiscono valori diversi diversi da zero per indicare diverse modalità di errore

AFAIK questo proviene dalla convenzione C che dovresti restituire 0 se è successo. Vedere:

 man close 

La maggior parte dell’API POSIX è costruita in questo modo. http://en.wikipedia.org/wiki/C_POSIX_library

Il tuo tentativo di equare vero / falso con successo / fallimento.

Sono due dicotomie completamente diverse, anche se in modo sottile all’inizio!

Nello script di shell, non esiste nulla di vero / falso. Le “espressioni” della shell non sono interpretate come vero / falso. Piuttosto, le “espressioni” della shell sono processi che hanno esito positivo o negativo.

Ovviamente, un processo potrebbe fallire per molte ragioni. Quindi abbiamo bisogno di un set di codici più grandi per mappare possibili fallimenti. Gli interi positivi fanno il trucco. D’altra parte, se il processo ha successo, significa che ha fatto esattamente quello che doveva fare. Poiché esiste un solo modo per farlo, abbiamo solo bisogno di un codice. 0 fa il trucco.

In C, stiamo creando un programma. In uno script di shell, stiamo eseguendo una serie di programmi per fare qualcosa.

Differenza!

è una convenzione che risale agli albori di Unix.

Per convenzione, tutte le chiamate di sistema restituiscono 0 se riescono, diversamente diverso da zero, perché quindi numeri diversi possono essere utilizzati per indicare diversi motivi di errore.

Le conchiglie seguono questa convenzione, 0 significa che l’ultimo comando è riuscito, diverso da zero altrimenti. Analogamente, il valore di ritorno diverso da zero è utile per i messaggi di errore di output: ad es. 1: “brain dead”, 2: “heartless” e così via.