it-swarm.com.de

Klammer in Ausdrucksarithmetik: 3 * (2 + 1)

expr scheint Klammern nicht zu mögen (wird in der Mathematik verwendet, um die Operatorpriorität zu explizieren):

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

Wie kann man die Priorität des Bedieners in Bash ausdrücken?

64
Nicolas Raoul

Eine andere Möglichkeit, let bash builtin zu verwenden:

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

Hinweis

Wie @ Stéphane Chazelas wies darauf hin , sollten Sie in bash((...)) Verwenden, um aus Gründen der Lesbarkeit über expr oder let zu rechnen.

Verwenden Sie für die Portabilität $((...)) like @ Bernhard answer .

41
cuonglm

Sie können stattdessen die arithmetische Erweiterung verwenden.

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

Meiner persönlichen Meinung nach sieht das ein bisschen besser aus als mit 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 Bewertung 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.

79
Bernhard

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

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

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

ksh hat auch ein let eingebaut, das dieselbe Art von arithmetischem Ausdruck übergeben wird, nicht zu etwas erweitert wird, sondern einen Exit-Status zurückgibt, der davon abhängt, ob der Ausdruck wie in 0 aufgelöst wird oder nicht expr:

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

Da das Zitieren es jedoch umständlich und nicht sehr gut lesbar macht (natürlich nicht im gleichen Maße wie expr), führte ksh auch eine alternative Form ((...)) Ein:

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

das ist viel besser lesbar und sollte stattdessen verwendet werden.

let und ((...)) sind nur in ksh, zsh und bash verfügbar. 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 Schalen mit eingebautem Rechenoperator:

  • csh/tcsh (eigentlich 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, ein expr eingebaut (tatsächlich mit test zusammengeführt), das jedoch später entfernt wurde.

40

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 Zahl und jeder Operator als separater Parameter übergeben werden. Somit:

expr 3 \* \( 2 + 1 \)

Wenn Sie nicht an einem antiken Unix-System aus den 1970er oder 1980er Jahren arbeiten, gibt es kaum einen Grund, expr zu verwenden. 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)))"

Das Konstrukt $((…)) erweitert sich zum Ergebnis des arithmetischen Ausdrucks (in Dezimalzahl geschrieben). Bash unterstützt wie die meisten Shells nur Integer Arithmetic Modulo 264 (oder Modulo 232 für ältere Versionen von Bash und einigen anderen 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 plain sh.

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

Zusätzlich zur Ganzzahlarithmetik bietet expr einige Funktionen zur Manipulation von Zeichenfolgen. Auch diese werden von Funktionen von POSIX-Shells subsumiert, 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 tun, aber Bash kann mit [[ STRING =~ REGEXP ]] (Mit einem andere Regexp-Syntax - expr ist ein klassisches Tool und verwendet BRE, Bash verwendet EHE).

Wenn Sie keine Skripte warten, die auf 20 Jahre alten Systemen ausgeführt werden, müssen Sie nicht wissen, dass expr jemals existiert hat. Verwenden Sie die Shell-Arithmetik.

Verwenden Sie Klammern mit Anführungszeichen:

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

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

13
Nicolas Raoul

Wenn Sie bc haben ..

echo '3 * (2 + 1)'|bc 
9                                                                    
1
rob