GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum funktioniert Bash `(())` nicht innerhalb von `[[]]`?

Die GNU-Bash-Manpage für [[..]] erklärt, dass der Operator einen bedingten Ausdruck ausführt und

Gibt einen Status von 0 zurück oder 1 abhängig von der Auswertung des bedingten Ausdrucks expression . Ausdrücke bestehen aus den Primärwörtern, die unten in Bedingte Bash-Ausdrücke beschrieben werden.

Aber der arithmetische Operator ist nicht Teil der unterstützten bedingten Ausdrücke (primaries ) in [[..]] was bedeutet, dass der Ausdruck gezwungen wird, als Zeichenfolgenvergleich ausgeführt zu werden, d. h.

(( $n < 3))

wird nicht im arithmetischen Kontext ausgeführt aber genauso einfacher lexikografischer (String-)Vergleich wie

[[ 100 < 3 ]] 

was immer wahr ergibt, weil die ASCII-Werte für 1 , 0 , 0 vor 3 erscheinen

Aber innerhalb von [[..]] arithmetische Operationen werden unterstützt, wenn Sie -lt verwenden , -gt

arg1 OP arg2

OP ist einer von -eq , -ne , -lt , -le , -gt , oder -ge . Diese arithmetischen binären Operatoren geben wahr zurück, wenn arg1 ist gleich, ungleich, kleiner als, kleiner oder gleich, größer als oder größer oder gleich arg2 .

Hatten Sie Ihren Ausdruck also geschrieben als

a=start; n=100; [[ " stop start status " =~ " $a " && $n -lt 3 ]] && echo ok || echo bad
bad

es hätte wie erwartet funktioniert.

Oder selbst wenn Sie die Verwendung arithmetischer Ausdrücke erzwungen hätten, indem Sie $ vorangestellt hätten vor ((..)) und schrieb es wie folgt (beachten Sie, dass bash kein dokumentiertes Verhalten für $((..)) hat innerhalb von [[..]] ). Das wahrscheinlich erwartete Verhalten ist, dass der arithmetische Ausdruck vor dem [[..]] erweitert wird ausgewertet und die resultierende Ausgabe wird in einem String-Kontext als [[ 0 ]] ausgewertet was eine nicht leere Zeichenfolge bedeutet.

a=start; n=5; [[ " stop start status " =~ " $a " && $(( $n < 3 )) ]] && echo ok || echo bad

Das Ergebnis würde trotzdem schlecht aussehen, weil der arithmetische Ausdruck innerhalb von [[..]] zerlegt in einen unären String, nicht leeren Vergleichsausdruck als

$(( 5 < 3 ))
0
[[ -n 0 ]]

Das Ergebnis der arithmetischen Auswertung 0 (false) wird vom Testoperator als Nicht-Null-Entität angenommen und auf der rechten Seite von && als wahr bestätigt . Dasselbe würde auch für den anderen Fall gelten, z. sagen Sie n=1

$(( 1 < 3 ))
1
[[ -n 1 ]]

Um es kurz zu machen, verwenden Sie die richtigen Operanden für arithmetische Operationen innerhalb von [[..]] .


(( ist ein "Schlüsselwort", das die arithmetische Anweisung einleitet. Innerhalb von [[ , Sie können jedoch keine anderen Anweisungen verwenden. Sie können Verwenden Sie jedoch Klammern, um Ausdrücke zu gruppieren, also (( ... )) ist:eine redundante "Doppelgruppe". Die folgenden sind aufgrund der Vorrangigkeit von < alle äquivalent und && :

  • [[ " stop start status " =~ " $2 " && (($#<3)) ]]
  • [[ " stop start status " =~ " $2 " && ($#<3) ]]
  • [[ " stop start status " =~ " $2 " && $#<3 ]]

Wenn Sie einen ganzzahligen Vergleich wünschen, verwenden Sie -lt statt < , aber Sie müssen auch nicht alles in [[ ... ]] einfügen . Sie können eine bedingte Anweisung und eine arithmetische Anweisung zusammen in einer Befehlsliste verwenden.

{ [[ " stop start status " =~ " $2 " ]] && (($#<3)) ; } || { echo "Usage $0 file_name command"; exit 1;}

In diesem Fall ... && ... || ... wird so funktionieren, wie Sie es erwarten, obwohl dies im Allgemeinen nicht der Fall ist. Bevorzugen Sie einen if Anweisung statt.

if [[ " stop start status " =~ " $2 " ]] && (($#<3)); then
  echo "Usage $0 file_name command"
  exit 1
fi

Linux
  1. Warum funktioniert das ~/.bash_profile nicht?

  2. Warum funktioniert die automatische Vervollständigung nicht, wenn ein Befehlsname nach „Quelle“ eingegeben wird?

  3. Warum funktioniert das Parent Shell Here-Dokument nicht für Unterbefehle in Dash, aber Bash funktioniert?

  4. Warum funktioniert `exit &` nicht?

  5. Warum funktioniert mein symbolischer Link nicht?

CentOS 8 VM funktioniert nicht in VirtualBox 5.2 unter Ubuntu 18.04

Warum funktioniert hostname --fqdn nicht auf meinem Ubuntu-Computer?

chmod funktioniert nicht

Warum wird eine Bash-While-Schleife nicht beendet, wenn sie zu einem beendeten Unterbefehl weitergeleitet wird?

Warum Linux Bridge nicht funktioniert

Probleme mit regulären Ausdrücken in Bash:[^negate] scheint nicht zu funktionieren