Warum ist 0 wahr, aber falsch ist 1 in der Shell?

121
false; echo $?

Das Obige wird ausgegeben 1, was im Widerspruch zu allen anderen mir bekannten Programmiersprachen steht.

Irgendein Grund dafür?

httpinterpret
quelle
3
Es steht auch im Einklang mit dem Unix-Weg ... geben Sie beim Erfolg nichts zurück.
Abdullah Jibaly
21
Weil ein Exit-Status kein Boolescher Wert ist. So einfach ist das.
Jens
2
Beachten Sie, dass dies falsekein Boolescher Wert ist, wie in anderen Programmiersprachen. Es ist nur ein Programm unter /bin/false( /usr/bin/falseauf einem Mac), das immer einen Fehler-Exit-Code 1 zurückgeben soll. Ähnlich für true. Es gibt hier also kein Casting. Es geht nur um Exit-Codes.
Mikhail Vasin
Eine Shell ist eine (Benutzer-) Schnittstelle zu einem Betriebssystem. Unix-Programme usw. folgen aus dem in den Antworten angegebenen Grund (Fähigkeit, mehr als einen Fehlergrund zu kommunizieren) der Konvention, mit 0 als OK zu beenden. Die Shell behält einfach diese Konvention bei, wodurch Konstrukte if myprog; then echo OK; fieinfach und intuitiv sind. Andernfalls müssten Sie jeden Test für den Erfolg eines Programms umkehren!
Peter - Monica

Antworten:

93

Es ist eine Konvention, aber eine besonders nützliche, wenn Sie darüber nachdenken. Wenn ein Programm erfolgreich ist, ist dies im Allgemeinen alles, was Sie wissen müssen. Wenn es jedoch fehlschlägt, müssen Sie möglicherweise alle Arten von Informationen über den Fehler kennen - warum es passiert ist, wie es behoben werden kann usw. Wenn Sie einen mittleren „Erfolg“ von Null und einen mittleren Fehler ungleich Null haben, können Sie ziemlich einfach auf Erfolg prüfen und untersuchen Sie den bestimmten Fehler, um weitere Details zu erhalten, wenn Sie möchten. Viele APIs und Frameworks haben eine ähnliche Konvention - Funktionen, die erfolgreich sind, geben 0 zurück, und solche, die fehlschlagen, geben einen Fehlercode zurück, der den jeweiligen Fehlerfall beschreibt.

Carl Norum
quelle
6
Ich verstehe diese Antwort, verstehe aber immer noch nicht, warum die Konvertierung von Bool in Int invertiert ist. Gibt es eine "Return Boolean Convention", die besagt: Wenn Sie true zurückgeben, bedeutet dies, dass keine Fehler vorliegen. Wenn Sie false zurückgeben, bedeutet dies, dass ein Fehler aufgetreten ist (wie die bekanntere "Integer = Error Code Convention").
Guillaume86
1
Angenommen, es gibt eine Konvertierung von Boolesch in Int, bedeutet dies, dass Sie die Antwort nicht wirklich verstanden haben. Null bedeutet Erfolg und alle 1, 2, ..., 255 sind Fehlercodes, die verschiedene Fehlerszenarien sinnvoll kommunizieren können. Ein besonderes Beispiel ist xargsdie Verwendung verschiedener Fehlercodes im Bereich um 127, um anzuzeigen, wie eine Gruppe von Befehlen fehlgeschlagen ist. Die Konvertierung, die durchgeführt werden kann, ist int to bool, wobei 0 dem Erfolg zugeordnet ist (was Sie vermutlich als true / 1 ausdrücken möchten; aber erkennen Sie, dass dies nur eine andere willkürliche Konvention ist) und alle anderen Werte zum Scheitern führen.
Tripleee
79

Bash ist eine Programmiersprache (Skriptsprache), aber auch eine Shell und eine Benutzeroberfläche. Wenn 0ein Fehler aufgetreten ist, kann das Programm nur eine Art von Fehler anzeigen.

In Bash ist jedoch jeder Wert ungleich Null ein Fehler, und wir können eine beliebige Zahl von 1-255 verwenden, um einen Fehler darzustellen. Dies bedeutet, dass wir viele verschiedene Arten von Fehlern haben können. 1ist ein allgemeiner Fehler, 126bedeutet, dass eine Datei nicht ausgeführt werden kann, 127bedeutet "Befehl nicht gefunden" usw. Hier ist eine Liste von Bash- Exit-Codes mit speziellen Bedeutungen, die einige der häufigsten Exit-Codes zeigen.

Es gibt auch viele Arten von Erfolg (Exit-Status ist 0). Wenn Sie jedoch erfolgreich sind, können Sie mit dem nächsten Schritt fortfahren. Sie können die Ergebnisse auf einem Bildschirm drucken oder einen Befehl ausführen usw.

Stefan Lasiewski
quelle
8
Diese pragmatische Antwort, die die Nützlichkeit einer Vielzahl von Rückkehrcodes zeigt, ist der Predigt einiger anderer Antworten vorzuziehen.
Javadba
1
Und nur zum Spaß möchte ich darauf hinweisen, dass /usr/include/sysexits.hNotizen Werte verlassen , die vielleicht ehrgeiziger sind, obwohl die Konvention, die sie darstellen, aus den 1980er Jahren stammt. Diese Konvention existiert außerhalb des Bereichs von Bash.
Ghoti
2
Eine großartige, einfache und pragmatische Erklärung. Dies muss oben sein.
Rey Leonard Amorato
3
„Wenn 0war Fehler, dann wird das Programm konnte nur vorhanden , eine Art von Fehler“ . Diese Aussage ist der Schlüssel und der Grund, warum diese Antwort ganz oben stehen sollte.
Rayryeng
1
@LuisLavaire Das ist undefiniertes Verhalten. In der Praxis neigt die Zahl dazu, abgeschnitten zu werden. aber es wäre definitiv nicht "falscher", wenn die Laufzeit eine Warnung erzeugen und / oder einfach abstürzen würde. Das Betriebssystem hat genau ein Byte für diese Informationen reserviert und der Versuch, mehr als ein Byte dort zu platzieren, ist definitiv ein Fehler. Aber die OS-Designer stießen wahrscheinlich am ersten Tag auf Abstürze und zuckten die Achseln. Sie entschieden, dass das Beste, was sie tun können, darin besteht, den Wert einfach abzuschneiden und weiterzumachen.
Tripleee
30

Hier gibt es zwei verwandte Probleme.

Zunächst die Frage des OP: Warum ist 0 wahr, aber falsch ist 1 in der Shell? und zweitens, warum geben Anwendungen 0 für Erfolg und ungleich Null für Fehler zurück?

Um die Frage des OP zu beantworten, müssen wir die zweite Frage verstehen. Die zahlreichen Antworten auf diesen Beitrag haben beschrieben, dass dies eine Konvention ist, und einige der Feinheiten aufgelistet, die diese Konvention bietet. Einige dieser Feinheiten sind unten zusammengefasst.

Warum geben Anwendungen 0 für Erfolg und ungleich Null für Fehler zurück?

Code, der eine Operation aufruft, muss zwei Dinge über den Beendigungsstatus der Operation wissen. Wurde die Operation erfolgreich beendet? [* 1] Und wenn die Operation nicht erfolgreich beendet wurde, warum wurde die Operation nicht erfolgreich beendet? Jeder Wert kann verwendet werden, um den Erfolg anzuzeigen. 0 ist jedoch bequemer als jede andere Zahl, da es zwischen Plattformen portierbar ist. Zusammenfassung der Antwort von xibo auf diese Frage am 16. August 2011:

Null ist codierungsunabhängig.

Wenn wir eins (1) in einem 32-Bit-Ganzzahlwort speichern wollten, wäre die erste Frage "Big-Endian-Wort oder Little-Endian-Wort?", Gefolgt von "Wie lange bilden die Bytes ein Little-Endian-Wort?" ", während Null immer gleich aussieht.

Es muss auch erwartet werden, dass einige Leute errno irgendwann zu char oder short werfen oder sogar schweben. (int) ((char) ENOLCK) ist nicht ENOLCK, wenn char nicht mindestens 8 Bit lang ist (7-Bit-ASCII-Zeichenmaschinen werden von UNIX unterstützt), während (int) ((char) 0) unabhängig von 0 ist architektonische Details von char.

Sobald festgestellt wurde, dass 0 der Rückgabewert für den Erfolg ist, ist es sinnvoll, einen Wert ungleich Null für den Fehler zu verwenden. Auf diese Weise können viele Exit-Codes die Frage beantworten, warum der Vorgang fehlgeschlagen ist.

Warum ist 0 wahr, aber falsch ist 1 in der Shell?

Eine der grundlegenden Anwendungen von Shells besteht darin, Prozesse durch Skripterstellung zu automatisieren. Normalerweise bedeutet dies, eine Operation aufzurufen und dann abhängig vom Exit-Status der Operation etwas anderes zu tun. Philippe A. hat in seiner Antwort auf diesen Beitrag das gut erklärt

In Bash- und Unix-Shells im Allgemeinen sind Rückgabewerte nicht boolesch. Sie sind ganzzahlige Exit-Codes.

Es ist dann notwendig, den Exit-Status dieser Operationen als booleschen Wert zu interpretieren. Es ist sinnvoll, einen erfolgreichen ( 0) Exit-Status auf true und einen Nicht-Null- / Failure-Exit-Status auf false abzubilden . Auf diese Weise können verkettete Shell-Befehle bedingt ausgeführt werden.

Hier ist ein Beispiel mkdir deleteme && cd $_ && pwd. Da die Shell 0 als wahr interpretiert, funktioniert dieser Befehl wie erwartet. Wenn die Shell 0 als falsch interpretieren würde, müssten Sie den interpretierten Exit-Status für jede Operation invertieren.

Kurz gesagt, es wäre unsinnig für die Shell, 0 als falsch zu interpretieren, da Anwendungen 0 für einen erfolgreichen Exit-Status zurückgeben.


[* 1]: Ja, häufig müssen Vorgänge mehr als nur eine einfache Erfolgsmeldung zurückgeben, aber das würde den Rahmen dieses Threads sprengen.

Siehe auch Anhang E im Advanced Bash-Scripting Guide

Axiopistie
quelle
2
Hallo, nur um zu betonen, dass, wenn die Shell Null als falsch und Nicht-Null als wahr interpretieren mkdir deleteme && cd _$ && pwdwürde , der Trick nicht wirklich scheitern würde; aber wir müssten es ersetzen durch mkdir deleteme || cd _$ || pwd, was meiner Meinung nach weit weniger klar ist, denn was wir eigentlich tun wollen, ist mkdir deleteme" und " cd _$" und " pwd... (wobei "und" hier seine Bedeutung aus der gewöhnlichen Sprache haben).
Rémi Peyre
1
Ich glaube, ich habe das in meiner Antwort behandelt. Um jedoch klar zu sein, reicht es beim Invertieren der Logik nicht aus, nur die &&Operatoren durch ||Operatoren zu ersetzen . Sie müssten das Gesetz von De Morgan vollständig anwenden. Siehe: en.wikipedia.org/wiki/De_Morgan%27s_laws
Axiopistie
1
Eine weitere Überlegung: Ich sehe mindestens drei Gründe, warum es allgemein selbstverständlich wäre, zu sagen, dass dies trueNull und nicht Null falseentspricht. Erstens, wenn ich Ihnen etwas sage, hängt „die Wahrheit gesagt zu haben“ von der Anzahl der Lügen ab, die ich erzählt habe: Entweder ist es Null und ich habe (global) die Wahrheit gesagt, oder es ist ungleich Null und ich habe gelogen. Dies ist im Wesentlichen dasselbe, andwenn man möchte, dass das Logische dem gemeinsamen „und“ der Addition entspricht (wenn man sich natürlich auf natürliche Zahlen beschränkt).
Rémi Peyre
1
(Fortsetzung vom vorherigen Kommentar). Der zweite Grund ist, dass es eine Wahrheit gibt, aber viele Nichtwahrheiten; Daher ist es bequemer, einen einzigen Wert für trueund alle anderen Werte für zuzuordnen false. (Dies entspricht im Wesentlichen den Überlegungen zu den Rückgabewerten von Programmen.)
Rémi Peyre
(Fortsetzung vom vorherigen Kommentar). Der dritte Grund ist, dass "wahr, dass wahr, dass A" dasselbe ist wie "wahr, dass A", "falsch, dass falsch, dass A" dasselbe ist wie "falsch, dass A" usw.; das trueverhält sich also als Multiplikativ 1 und falseals Multiplikativ -1. Was als Potenzen von -1 bedeutet, dass truesich das Verhalten zusätzlich als "gerade" und falseals "ungerade" verhält . Wieder ist es das, truewas es verdient, Null zu sein ...
Rémi Peyre
17

Der eine grundlegende Punkt, den ich für wichtig halte, ist dieser. In Bash- und Unix-Shells im Allgemeinen sind Rückgabewerte nicht boolesch. Sie sind ganzzahlige Exit-Codes. Daher müssen Sie sie gemäß der Konvention bewerten, die besagt, dass 0 Erfolg bedeutet und andere Werte einen Fehler bedeuten.

Mit test, [ ]oder [[ ]]Betreiber bewerten bash Bedingungen als wahr im Falle eines Exit - Code 0 (das Ergebnis von / bin / true). Andernfalls werden sie als falsch bewertet.

Zeichenfolgen werden anders ausgewertet als Exit-Codes:

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

if [ -z "" ] ; then echo null ; fi

Der (( ))arithmetische Operator interpretiert 1 und 0 als wahr und falsch. Aber das Operator kann nicht als vollwertiger Ersatz verwendet wird für test, [ ]oder [[ ]]. Hier ist ein Beispiel, das zeigt, wann der arithmetische Operator nützlich ist:

for (( counter = 0 ; counter < 10 ; counter ++ )) ; do
  if (( counter % 2 )) ; then echo "odd number $counter" ; fi
done
Philippe A.
quelle
Vielen Dank für die Erklärung der Klammern gegen Klammern auf wahr / falsch
Javadba
15

Es ist nur eine Konvention, dass ein 0-Exit-Code Erfolg bedeutet. EXIT_SUCCESS wird auf fast jedem modernen System 0 sein.

BEARBEITEN:

"Warum geben Test 0 und Test 1 0 zurück (Erfolg)?"

Das ist eine ganz andere Frage. Die Antwort lautet, dass das Übergeben eines einzelnen Arguments zum Testen immer zum Erfolg führt, es sei denn, dieses Argument ist die Nullzeichenfolge (""). Siehe die Open Group-Dokumentation .

Matthew Flaschen
quelle
Warum dann beides test 0und test 1gibt 0 zurück (Erfolg)?
httpinterpret
5
@httpinterpret, testet testkeine numerischen Werte. Es wird geprüft, ob diese Zeichenfolge die Nullzeichenfolge ist oder nicht. man testfür mehr Informationen.
Carl Norum
12

Normalerweise geben Programme für den Erfolg Null und für den Fehler ungleich Null zurück. falseGibt 1 zurück, da es sich um einen geeigneten Wert ungleich Null handelt. Im Allgemeinen bedeutet jedoch jeder Wert ungleich Null einen Fehler, und viele Programme geben unterschiedliche Werte ungleich Null zurück, um unterschiedliche Fehlermodi anzuzeigen

Michael Mrozek
quelle
2
Downvotes ohne Erklärung (oder offensichtlichen Grund) sind scheiße und diejenigen, die es tun, sind lahm, weil sie der Community überhaupt nicht helfen.
Abdullah Jibaly
1
Nicht dulden ... aber es sind ihre 2 Punkte ... und @MichaelMrozek ... mit 19,6k kann es nicht so schlimm schaden, lol.
Alex Gray
1
@alexgray Das war vor zwei Jahren; Zu der Zeit hatte ich ungefähr 5k. Und ich war neugieriger, was mit der Antwort falsch war als über den Repräsentanten
Michael Mrozek
4

Es ist eine Konvention, die bis in die frühen Tage von Unix zurückreicht.

Konventionell geben alle Systemaufrufe 0 zurück, wenn sie erfolgreich sind, andernfalls ungleich Null, da dann unterschiedliche Zahlen verwendet werden können, um unterschiedliche Fehlerursachen anzuzeigen.

Shells folgen dieser Konvention. 0 bedeutet, dass der letzte Befehl erfolgreich war, andernfalls ungleich Null. In ähnlicher Weise ist der Rückgabewert ungleich Null nützlich für Ausgabefehlermeldungen: z. B. 1: "hirntot", 2: "herzlos" usw.


quelle
Das ist die Antwort.
Peter - Monica
3

Sie versuchen, wahr / falsch mit Erfolg / Misserfolg gleichzusetzen.

Es sind zwei völlig, wenn auch zunächst subtil unterschiedliche Dichotomien!

In Shell-Skripten gibt es kein Richtig / Falsch. Shell-Ausdrücke werden nicht als wahr / falsch interpretiert. Shell-Ausdrücke sind vielmehr Prozesse, die entweder erfolgreich sind oder fehlschlagen.

Offensichtlich kann ein Prozess aus vielen Gründen fehlschlagen. Daher benötigen wir einen größeren Satz von Codes, um mögliche Fehler abzubilden. Die positiven ganzen Zahlen machen den Trick. Wenn der Prozess jedoch erfolgreich ist, bedeutet dies, dass er genau das getan hat, was er tun sollte. Da es nur einen Weg gibt, benötigen wir nur einen Code. 0 macht den Trick.

In C erstellen wir ein Programm. In einem Shell-Skript führen wir eine Reihe von Programmen aus, um etwas zu erledigen.

Unterschied!

Captaincurrie
quelle
Es ist verwirrend. Geben Sie 'man [' ein. Es zeigt Das Testdienstprogramm wertet den Ausdruck aus und gibt, wenn es als wahr ausgewertet wird, einen Exit-Status von Null (wahr) zurück. Andernfalls wird 1 (false) zurückgegeben. Wenn kein Ausdruck vorhanden ist, gibt test auch 1 (false) zurück.
Kavalkade
1

Vielleicht ist ein guter Weg, sich daran zu erinnern ,:

  • Rückkehrcodes antworten "Was ist die Antwort?" wahr (oder ein anderes Ergebnis) oder falsch
  • Ausstiegscodes antworten "Was ist das Problem?" Exit-Code oder kein Problem (0)
jjisnow
quelle