Wie wird bash folgenden Code auswerten?

7

Diese Frage besteht aus zwei Teilen:

(a) Verstehen, was der abgeschnittene Code tut

(b) Verständnis des Unterschieds zwischen Exit-Status und Return-Status im Kontext von bash.

Hier ist der Code, den ich zu verstehen versuche:

if var=-2 && (( var+=2 ))
then
    echo "True"
else
    echo "False"
fi

Das Ausführen erzeugt False. Ich kann nicht verstehen, warum das passiert.

Wenn ich das richtig verstehe, passiert hier vielleicht was mit der ifBedingung:

(a) var=-2erstellt den Exit-Status 0, da die Zuweisung erfolgreich ist

(b) (( var+=2 ))addiert 2 zum Wert von varund der Ausdruck wertet Null aus. Der Exit-Status ist also 1 für diesen Begriff

(c) 0 && 1 erzeugt einen existierenden Status von 0, der dann vom ifKonstrukt verwendet wird

Das ifKonstrukt soll einfach den Exit-Status überprüfen und wenn es Null ist, nimmt es den Then- Pfad. In Schritt (c) oben ist es Null, aber das Skript nimmt immer noch den else- Pfad. Ist das richtig, um das zu verstehen?

Außerdem sehe ich immer wieder, dass verschiedene bashTexte den Exit-Status und den Return-Status austauschbar verwenden.

Ich bezweifle, dass die var=-2Zuweisung einen Exit-Status haben würde, da es sich nicht um ein Programm handelt. Aber jede Klarstellung über den Unterschied zwischen zwei wird großartig sein.

sshekhar1980
quelle
1
Führen Sie es mit aus, um #!/bin/bash -xzu sehen, was passiert
Rui F Ribeiro
1
+ var = -2 + ((var + = 2)) + echo 'Falscher Pfad wird ausgewertet' Dies hilft mir nicht zu verstehen, welchen Exit-Status / Return-Status das if-Konstrukt sieht. Es geht darum, das Konstrukt zu verstehen und nicht kryptisch zu sein.
sshekhar1980
from man bash: expression1 && expression2 True, wenn sowohl expression1 als auch expression2 true sind. Ausdruck1 || expression2 True, wenn entweder expression1 oder expression2 true ist. Die && und || Operatoren bewerten expression2 nicht, wenn der Wert von expression1 ausreicht, um den Rückgabewert des gesamten bedingten Ausdrucks zu bestimmen.
MiniMax
1
Ihr Missverständnis scheint in (c) zu sein, insbesondere "0 && 1 erzeugt einen Existenzstatus von 0." 0 && 1in der Tat ist 1.
Kevin
Dies ist aus genau dem gleichen Grund i=0; ((i++))ein fehlgeschlagener Exit-Status, während i=0; ((++i))ein erfolgreicher ist. In einem arithmetischen Kontext sind positive ganze Zahlen wahr und Null ist falsch.
Charles Duffy

Antworten:

10

Das ist:

if
  first list of commands
then
  second list of commands
else
  third list of commands
fi

Dies dient zum Ausführen der zweiten Befehlsliste, wenn die erste Befehlsliste mit einem Exit-Status true / success (Null) zurückgegeben wird, dh wenn der zuletzt ausgeführte Befehl dort mit einem Exit-Status Null zurückgegeben wird.

Im:

var=-2 && ((var += 2))

Es ist , cmd1 && cmd2wo cmd2nur ausgeführt werden, wenn cmd1erfolgreich ist.

var=-2

Ist normalerweise erfolgreich, solange $vares nicht schreibgeschützt ist. Daher wird der ((var += 2))Befehl ausgeführt:

((arithmetic expression))

Gibt success / true zurück , solange der Ausdruck korrekt ausgewertet wird (kein Syntaxfehler) und das Ergebnis des Ausdrucks ungleich Null ist.

  • ((123)), ((1 + 1)), ((1 == 1))Return true
  • ((0)), ((-2 + 2)), ((2 == -2))Return false.
  • ((4294967296 * 4294967296)) In den meisten Shells wird aufgrund des 64-Bit-Integer-Wrappings false zurückgegeben

var += 2führt als arithmetischer Ausdruck die Zuweisung durch und löst den zugewiesenen Wert auf, hier 0, daher der falsche Exit-Status.

Sie können den Wert, auf dem der Exit-Status basiert, mithilfe der $((...))arithmetischen Erweiterungssyntax anzeigen:

$ echo "$((1 + 1)) $((2 == 2)) $((2 == -2)) $((var = -2)) $((var += 2))"
2 1 0 -2 0

Oder einer Variablen zuweisen:

$ var=-2; ((result = (var += 2)))
$ echo "$? $result $var"
1 0 0

$?enthält den Exit-Status des vorherigen Befehls. Für if/ then/ else/ fibedeutet 0 wahr, alles andere falsch.

Die Verwirrung hier kommt von der Tatsache, dass es für arithmetische Ausdrücke umgekehrt ist: 0bedeutet falsch und alles andere bedeutet wahr (zum Beispiel 2 == 2ist 1während 2 < 1ist 0).

Um sich keine Sorgen über den Unterschied zu machen, vergessen Sie einfach $?die möglichen Werte. Man denke nur in Bezug auf die boolean wahr / falsch , Erfolg / Misserfolg .

 grep -q foo file

Gibt true zurück, wenn fooin gefunden wird file.

 [ "$a" = "$b" ]

Gibt true zurück, wenn es $adasselbe enthält wie $b.

 ((6 * 3 - 12))
 ((4 == 1))

Geben Sie true zurück, wenn das Ergebnis des arithmetischen Ausdrucks eine Zahl ungleich Null ist.

Es spielt keine Rolle, ob diese wahr / falsch als 0 oder 1 des Exit-Status dieser grep/ [Befehle oder ((...))Konstrukte ausgedrückt werden .

Stéphane Chazelas
quelle
Sie irren sich hier: "Die Verwirrung hier kommt von der Tatsache, dass es für arithmetische Ausdrücke umgekehrt ist: 0 bedeutet falsch und alles andere bedeutet wahr (zum Beispiel 2 == 2 ist 1, während 2> 1 0 ist). "" Ich habe diese Beispiele ausgeführt und erhalten:((2==2)); echo $? output 0 ((2 > 1)); echo $? output 0
MiniMax
@MiniMax, du vermisst meinen Standpunkt. Der 2==2arithmetische Ausdruck führt zu 1(siehe echo "$((2==2))"), da das ((...))Konstrukt nicht 0 ist, gibt es true zurück (es gibt den Exit-Status 0 zurück, aber wie gesagt, Sie müssen sich im Allgemeinen keine Gedanken darüber machen, welcher Exit-Code true oder false bedeutet)
Stéphane Chazelas
Jetzt verstehe ich Ihren Punkt. Aber warum ist 2> 1 überhaupt falsch? $ ((2> 1)) ist return 0, ja, daher ist es nach Ihrer Logik falsch. Hier bedeutet "0 falsch und alles andere wahr (zum Beispiel 2 == 2 ist 1, während 2> 1 0 ist)". Ich kann diesen Satz nicht verstehen.
MiniMax
Wow, $ ((2> 1)) Ergebnisse 1. :) Jetzt überprüft.
MiniMax
@MiniMax Entschuldigung, das war ein Tippfehler. Jetzt behoben.
Stéphane Chazelas
3

(c) 0 && 1 erzeugt einen existierenden Status von 0, der dann vom ifKonstrukt verwendet wird

Da ist der Fehler. 0 && 1 ergibt 1. Dies ist nicht C oder Java, denken Sie daran. In der Shell ist 0 && 1 das, was Sie bekommen würden true && false.

$ true; echo $?
0
$ false; echo $?
1
$ true && false; echo $?
1

Außerdem sehe ich immer wieder, dass verschiedene Bash-Texte den Exit-Status und den Return-Status austauschbar verwenden.

Sie sind austauschbar. Was Sie beachten möchten, ist, dass dies 0auf Erfolg und nicht 0auf Misserfolg hinweist. Es ist das Gegenteil der meisten Programmiersprachen, in denen 0es falsch und 1wahr ist.

John Kugelman
quelle
Gute Antwort, soweit es geht, aber die Unterscheidung zwischen arithmetischem Wert und Exit-Status ist wichtig und scheint nicht explizit definiert zu sein. Ich bin nicht sicher, ob das OP versteht, warum sich eine arithmetische Operation mit einem Ergebnis von 0von einem Befehl mit einem Exit-Status von unterscheidet 0.
Charles Duffy
0

Alles funktioniert wie erwartet.

if var=-2 && (( var+=2 ))
then
    echo "True"
else
    echo "False"
fi

Code Erklärung: -

if var=-2 && (( var+=2 ))

var=-2 => true Der Wert ist ungleich Null und wird daher als wahr bewertet

var+=2 => false Der Wert ist Null und wird daher als falsch bewertet

das ist wie

if true && false

Gemäß logischer Berechnung wahr && falsch => falsch

In diesem Fall ist hier unser endgültiger Code

if (false)
then
    echo "True"
else
    echo "False"
fi
Deepak Dixit
quelle
3
var=0, var=-2als wahr bewerten. Der Wert der Zuordnung spielt hier keine Rolle. var=1$(false)würde false zurückgeben. ((var=0))würde false zurückgeben, ((var=1$(false)))würde true zurückgeben.
Stéphane Chazelas