Klammern in Ausdrucksarithmetik: 3 * (2 + 1)

expr scheint Klammern (verwendet) nicht zu mögen in der Mathematik zur expliziten Operatorpriorität):

expr 3 * (2 + 1) bash: syntax error near unexpected token `(" 

Wie wird die Operatorpriorität in bash ausgedrückt?

Antwort

Eine andere Möglichkeit, let bash zu verwenden:

$ let a="3 * (2 + 1)" $ printf "%s\n" "$a" 9 

Hinweis

Wie @ Stéphane Chazelas hervorhob In bash sollten Sie ((...)) verwenden, um über expr oder zu rechnen let zur besseren Lesbarkeit.

Verwenden Sie für die Portabilität $((...)) wie @Bernhard Antwort .

Kommentare

  • +1 Noch besser lesbar! Ich habe meine Frage + Antwort gepostet, nur weil ich dachte, es wäre hilfreich für meine Linux-Kollegen, aber jetzt profitiere ich sehr von den anderen Antworten 🙂
  • Dort ‚ ist kein Grund, let zu verwenden. ‚ ist nicht standardmäßiger oder portabler als (( a = 3 * (2 + 1) )) (beide stammen von ksh und sind nur in ksh, bash und zsh verfügbar) und ‚ ist weniger lesbar oder leicht zu zitieren. Verwenden Sie a=$((3 * (2 + 1))), um portabel zu sein.
  • Ich ‚ sage es nicht ‚ ist falsch, ich ‚ sage nur, dass es nicht verwendet werden sollte, da es bessere Alternativen gibt (eine für die Lesbarkeit ((a = 3 * (2 + 1) )), eine Aus Gründen der Portabilität a=$((3 * (2 + 1)))) ist ‚ keine Notiz gegen Sie oder Ihre Antwort, sondern dagegen, dass sie die ausgewählte Antwort und der Topscorer ist .
  • @St é phaneChazelas: Meine Antwort wurde aktualisiert!
  • Ich habe immer a=1 $[a+2] oder a=1 b=2 $[a+b]. Ist ihr Grund, diese Syntax zu vermeiden?

Antwort

Sie können stattdessen die arithmetische Erweiterung verwenden. P. >

echo "$(( 3 * ( 2 + 1 ) ))" 9 

Meiner persönlichen Meinung nach sieht dies etwas besser aus als die Verwendung von expr.

Von man bash

Arithmetische Erweiterung Die arithmetische Erweiterung ermöglicht die Auswertung eines arithmetischen Ausdrucks und die Substitution des Ergebnisses. Das Format für die arithmetische Erweiterung lautet:

 $((expression)) 

Der Ausdruck wird so behandelt, als ob er sich in doppelten Anführungszeichen befindet, ein doppeltes Anführungszeichen in Klammern wird jedoch nicht speziell behandelt. Alle Token im Ausdruck werden einer Parametererweiterung, Zeichenfolgenerweiterung, Befehlssubstitution und Anführungszeichenentfernung unterzogen. Arithmetische Erweiterungen können verschachtelt sein.

Die Auswertung erfolgt nach den unten unter ARITHMETISCHE BEWERTUNG aufgeführten Regeln. Wenn der Ausdruck ungültig ist, gibt bash eine Meldung aus, die auf einen Fehler hinweist, und es erfolgt keine Ersetzung.

Kommentare

  • Abgesehen von der Lesbarkeit ist für ‚ kein zusätzlicher Prozess erforderlich, um die Arithmetik durchzuführen. ‚ wird von der Shell selbst verarbeitet.
  • Beachten Sie, dass in POSIX-Shells ‚ dem Wort unterliegt Teilen, so dass es ‚ eine gute Angewohnheit ist, es in Listenkontexten zu zitieren.
  • Wenn ich dies an der Bash-Shell versuche, erhalte ich ‚ Unzulässiger Variablenname. “

Antwort

Es gibt keinen Grund, expr für die Arithmetik in modernen Shells zu verwenden.

POSIX definiert die $((...)) Erweiterungsoperator. Sie können dies also in allen POSIX-kompatiblen Shells verwenden (die sh aller modernen Unix-Likes, Dash, Bash, Yash, Mksh, Zsh, Posh, Ksh … ).

a=$(( 3 * (2 + 1) )) a=$((3*(2+1))) 

ksh führte auch eine let ein, die eingebaut wurde Wird die gleiche Art von arithmetischem Ausdruck übergeben, wird nicht zu etwas erweitert, sondern es wird ein Exit-Status zurückgegeben, der davon abhängt, ob der Ausdruck aufgelöst wird es auf 0 oder nicht, wie in expr:

if let "a = 3 * (2 + 1)"; then echo "$a is non-zero" fi 

Da das Anführungszeichen es jedoch umständlich macht und nicht Sehr gut lesbar (natürlich nicht im gleichen Umfang wie expr), führte ksh auch eine ((...)) alternative Form:

if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then echo "$a is non-zero and 3 > 1" fi ((a+=2)) 

, die viel besser lesbar ist und stattdessen verwendet werden sollte.

let und ((...)) sind nur in ksh, zsh und bash.Die Syntax $((...)) sollte bevorzugt werden, wenn eine Portabilität auf andere Shells erforderlich ist. expr wird nur für Bourne-ähnliche Shells vor POSIX benötigt (normalerweise) die Bourne-Shell oder frühere Versionen der Almquist-Shell).

Auf der Nicht-Bourne-Front gibt es einige Shells mit integriertem arithmetischen Operator:

  • csh / tcsh (tatsächlich die erste Unix-Shell mit integrierter arithmetischer Auswertung):

    @ a = 3 * (2 + 1) 
  • akanga (basierend auf rc)

    a = $:"3 * (2 + 1)" 
  • Als Verlaufsnotiz hatte die Originalversion der Almquist-Shell, wie sie 1989 im Usenet veröffentlicht wurde, eine expr integriert (tatsächlich zusammengeführt mit test), wurde aber später entfernt.

Kommentare

  • Ich lerne jeden Tag etwas Neues von dir, St é phane. Ich schätze Ihr Wissen über die POSIX-Shell sehr!
  • Wie wäre es mit : $((a = a*2))?
  • Was ist, wenn ich einen Gleitkomma habe? Mein Ausdruck ist a = $ ((-14 + 0,2 * (1 + 2 + 3))). Das Fehlertoken lautet “ .2 * (1 + 2 + 3) “
  • @Blaise, dann Sie ‚ d benötigt eine Shell, die Gleitkommazahlen in $((...)) wie zsh, ksh93 oder yash unterstützt.

Antwort

expr ist ein externer Befehl, keine spezielle Shell-Syntax. Wenn Sie also möchten, dass expr Shell-Sonderzeichen anzeigt, müssen Sie sie durch Zitieren vor Shell-Parsing schützen. Darüber hinaus muss für expr jede Nummer und jeder Operator als separater Parameter übergeben werden. Also:

expr 3 \* \( 2 + 1 \) 

Wenn Sie nicht an einem antiken Unix-System aus den 1970er oder 1980er Jahren arbeiten, gibt es kaum einen Grund, . Früher hatten Shells keine eingebaute Möglichkeit, Arithmetik auszuführen, und Sie mussten stattdessen das Dienstprogramm expr aufrufen. Alle POSIX-Shells verfügen über eine integrierte Arithmetik über die Syntax arithmetische Erweiterung .

echo "$((3 * (2 + 1)))" 

The Das Konstrukt $((…)) wird zum Ergebnis des arithmetischen Ausdrucks (in Dezimalzahl geschrieben) erweitert. Bash unterstützt, wie die meisten Shells, nur ganzzahlige arithmetische Modulo 2 64 (oder Modulo 2 32 für ältere Versionen von Bash und einige andere Shells auf 32-Bit-Computern).

Bash bietet eine zusätzliche Komfortsyntax , wenn Sie Zuweisungen ausführen oder testen möchten, ob ein Ausdruck 0 ist, sich aber nicht um das Ergebnis kümmern. Dieses Konstrukt existiert auch in ksh und zsh, jedoch nicht in normalem sh.

((x = 3 * (2+1))) echo "$x" if ((x > 3)); then … 

Zusätzlich zur Ganzzahlarithmetik expr bietet einige Funktionen zur Manipulation von Zeichenfolgen. Auch diese werden von Funktionen von POSIX-Shells zusammengefasst, mit einer Ausnahme: expr STRING : REGEXP testet, ob die Zeichenfolge mit dem angegebenen regulären Ausdruck übereinstimmt. Eine POSIX-Shell kann dies nicht ohne externe Tools, aber Bash kann mit [[ STRING =~ REGEXP ]] (mit einer anderen Regexp-Syntax expr ist ein klassisches Tool und verwendet BRE, bash verwendet ERE).

Es sei denn, Sie warten Skripte Wenn Sie auf 20 Jahre alten Systemen laufen, müssen Sie nicht wissen, dass expr jemals existiert hat. Verwenden Sie die Shell-Arithmetik.

Kommentare

  • expr foo : '\(.\)' führt auch die Textextraktion durch. bash ‚ s BASH_REMATCH erreicht etwas Ähnliches. Es wird auch ein Zeichenfolgenvergleich durchgeführt, den POSIX [ nicht durchführt (obwohl man sich vorstellen könnte, sort dafür zu verwenden).
  • als Syntaxplatzhalter unterstreichen — Sie ein Schemer, @Giles? :]
  • @RubyTuesdayDONO Ich habe ‚ hier keinen Unterstrich verwendet. Lesen Sie U + 2026 HORIZONTAL ELLIPSIS falsch? Wenn ja, versuchen Sie es mit einer größeren Schriftart.
  • @Giles – okay, ja, aufgrund meiner Schriftgröße sieht es nur wie ein Unterstrich aus. Für mich ist “ Schemer “ eine Ergänzung, und ‚ ist keine Ellipse versus Unterstrich ändert ohnehin die Bedeutung… es ist nicht nötig, darüber nachzudenken: /

Antwort

Verwenden Sie Klammern mit Anführungszeichen:

expr 3 "*" "(" 2 "+" 1 ")" 9 

Die Anführungszeichen verhindern, dass bash die Klammer als bash-Syntax interpretiert.

Kommentare

  • Was Nicolas illustriert, aber nicht erklärt, ist, dass die Token in der expr -Befehlszeile durch Leerzeichen getrennt werden müssen. so; Beispiel: expr 3 "*" "(2" "+" "1)" funktioniert nicht . (Übrigens müssen Sie wahrscheinlich nicht die + angeben.)
  • Die Klammern sind keine ‚ t Schlüsselwörter wie while und [[, sie ‚ sind Syntax. Wenn sie Schlüsselwörter wären, würden sie ‚ in Befehlsargumenten nicht als solche interpretiert. Sie benötigen Anführungszeichen, damit bash sie nicht ‚ analysiert, sondern stattdessen ein Zeichenfolgenliteral sieht.

Antwort

Wenn Sie bc ..

echo "3 * (2 + 1)"|bc 9 

haben

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.