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 vonksh
und sind nur in ksh, bash und zsh verfügbar) und ‚ ist weniger lesbar oder leicht zu zitieren. Verwenden Siea=$((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äta=$((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]
odera=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 aufrc
)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 mittest
), 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
‚ sBASH_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