Nawias w arytmetyce wyrażenia: 3 * (2 + 1)

expr nie lubi nawiasów (używane w matematyce do jawnego priorytetu operatora):

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

Jak wyrazić priorytet operatora w bash?

Odpowiedź

Inny sposób korzystania z let wbudowanego bash:

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

Uwaga

Jak wskazał @ Stéphane Chazelas , w bash powinieneś użyć ((...)) do wykonywania działań arytmetycznych w expr lub let dla czytelności.

Aby zapewnić przenośność, użyj $((...)) jak @Bernhard answer .

Komentarze

  • +1 Jeszcze bardziej czytelne! Opublikowałem swoje pytanie + odpowiedź, myśląc, że byłoby to pomocne dla innych użytkowników Linuksa, ale teraz wiele korzyści przyniosą mi inne odpowiedzi 🙂
  • Tam ' nie ma powodu, aby używać let. ' nie jest bardziej standardowe ani przenośne niż (( a = 3 * (2 + 1) )) (oba pochodzą z ksh i są dostępne tylko w ksh, bash i zsh) i ' są mniej czytelne lub łatwe do zacytowania. Użyj a=$((3 * (2 + 1))) jako przenośnego.
  • I ' nie mówię tego ' jest źle, ' mówię tylko, że nie należy go używać, ponieważ istnieją lepsze alternatywy (jedna dla czytelności ((a = 3 * (2 + 1) )), jedna za przenośność a=$((3 * (2 + 1)))), więc ' nie jest uwagą przeciwko Tobie lub Twojej odpowiedzi, ale przeciwko temu, że jest wybraną odpowiedzią i najlepszym strzelcem .
  • @St é phaneChazelas: Zaktualizowałem odpowiedź!
  • Zawsze używałem a=1 $[a+2] lub a=1 b=2 $[a+b]. Czy ich powód, aby unikać tej składni?

Odpowiedź

Zamiast tego możesz użyć rozwinięcia arytmetycznego.

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

Moim zdaniem wygląda to trochę ładniej niż użycie expr.

Od man bash

Rozszerzenie arytmetyczne Interpretacja arytmetyczna pozwala na ocenę wyrażenia arytmetycznego i podstawienie wyniku. Format interpretacji wyrażeń arytmetycznych jest następujący:

 $((expression)) 

Wyrażenie jest traktowane tak, jakby znajdowało się w cudzysłowie, ale podwójny cudzysłów w nawiasach nie jest traktowany specjalnie. Wszystkie tokeny w wyrażeniu podlegają interpretacji parametrów, interpretacji ciągów, podstawianiu poleceń i usuwaniu cytatów. Rozszerzenia arytmetyczne mogą być zagnieżdżane.

Ocena jest wykonywana zgodnie z regułami wymienionymi poniżej w EWALUACJA ARYTMETYCZNA. Jeśli wyrażenie jest nieprawidłowe, bash drukuje komunikat wskazujący błąd i nie następuje żadne podstawienie.

Komentarze

  • Oprócz czytelności, nie wymaga również ' t wymaga rozwidlenia dodatkowego procesu do wykonania arytmetyki; jest ' jest obsługiwany przez samą powłokę.
  • Zauważ, że w powłokach POSIX, ' podlega słowom dzielenie, więc ' jest dobrym zwyczajem cytowania tego w kontekstach list.
  • Kiedy próbuję tego w powłoce bash, otrzymuję ' Niedozwolona nazwa zmiennej. ”

Odpowiedź

Nie ma powodu, aby używać expr do arytmetyki w nowoczesnych powłokach.

POSIX definiuje $((...)) operator rozwinięcia. Możesz więc użyć tego we wszystkich powłokach zgodnych z POSIX (sh wszystkich współczesnych uniksopodobnych, myślnik, bash, yash, mksh, zsh, posh, ksh … ).

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

ksh wprowadzono również wbudowaną let, w której jest przekazywany ten sam rodzaj wyrażenia arytmetycznego, nie rozwija się do czegoś, ale zwraca kod zakończenia w oparciu o to, czy wyrażenie zostało rozwiązane es na 0 lub nie, jak w expr:

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

Jednak cytowanie sprawia, że jest to niewygodne i nie bardzo czytelne (oczywiście nie w takim samym stopniu jak expr), ksh wprowadził także ((...)) alternatywna forma:

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

, która jest dużo bardziej czytelna i powinna być używana zamiast niej.

let i ((...)) są dostępne tylko w ksh, zsh i bash.Składnia $((...)) powinna być preferowana, jeśli potrzebna jest przenośność na inne powłoki, expr jest wymagana tylko dla powłok podobnych do Bournea w wersji wcześniejszej niż POSIX (zazwyczaj powłoka Bournea lub wczesne wersje powłoki Almquist).

Na froncie innym niż Bourne jest kilka powłok z wbudowanym operatorem arytmetycznym:

  • csh / tcsh (właściwie pierwsza powłoka Uniksa z wbudowaną funkcją obliczania arytmetycznego):

    @ a = 3 * (2 + 1) 
  • akanga (na podstawie rc)

    a = $:"3 * (2 + 1)" 
  • jako notatka historyczna, oryginalna wersja powłoki Almquist, opublikowana w usenecie w 1989 r., miała expr wbudowany (faktycznie połączony z test), ale został później usunięty.

Komentarze

  • Codziennie uczę się od ciebie czegoś nowego, św. é phane. Bardzo doceniam twoją znajomość powłoki POSIX!
  • A co z : $((a = a*2))?
  • A co jeśli mam zmiennoprzecinkowe? Moje wyrażenie to a = $ ((-14 + 0,2 * (1 + 2 + 3))). Token błędu to ” .2 * (1 + 2 + 3) ”
  • @Blaise, a następnie ' d potrzebujesz powłoki obsługującej zmiennoprzecinkowe w $((...)), takiej jak zsh, ksh93 lub yash.

Odpowiedź

expr to polecenie zewnętrzne, a nie specjalna składnia powłoki. Dlatego, jeśli chcesz, aby expr widziało znaki specjalne powłoki, musisz je chronić przed analizowaniem powłoki przez cytowanie. Ponadto expr wymaga, aby każda liczba i operator były przekazywane jako oddzielny parametr. Tak więc:

expr 3 \* \( 2 + 1 \) 

Jeśli nie pracujesz na starym systemie uniksowym z lat 70. lub 80., nie ma powodu, aby używać expr. W dawnych czasach powłoki nie miały wbudowanego sposobu wykonywania działań arytmetycznych i zamiast tego trzeba było wywołać narzędzie expr. Wszystkie powłoki POSIX mają wbudowaną arytmetykę za pomocą składni interpretacji arytmetycznej .

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

konstrukcja $((…)) rozwija się do wyniku wyrażenia arytmetycznego (zapisanego w systemie dziesiętnym). Bash, jak większość powłok, obsługuje tylko arytmetykę całkowitą modulo 2 64 (lub modulo 2 32 dla starszych wersji basha i niektórych innych powłok na komputerach 32-bitowych).

Bash oferuje dodatkową wygodną składnię , gdy chcesz wykonać przypisania lub sprawdzić, czy wyrażenie ma wartość 0, ale nie przejmujesz się wynikiem. Ta konstrukcja istnieje również w ksh i zsh, ale nie w zwykłym sh.

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

Oprócz arytmetyki liczb całkowitych expr oferuje kilka funkcji służących do manipulacji na łańcuchach. Te również są podliczane przez cechy powłok POSIX, z wyjątkiem jednej: expr STRING : REGEXP sprawdza, czy łańcuch pasuje do określonego wyrażenia regularnego. Powłoka POSIX nie może tego zrobić bez narzędzia zewnętrzne, ale bash może z [[ STRING =~ REGEXP ]] (z inną składnią wyrażenia regularnego expr to klasyczne narzędzie i używa BRE, bash używa ERE).

Chyba że utrzymujesz skrypty które działają na 20-letnich systemach, nie musisz wiedzieć, że expr kiedykolwiek istniał. Użyj arytmetyki powłoki.

Komentarze

  • expr foo : '\(.\)' również wyodrębnia tekst. bash ' s BASH_REMATCH osiąga coś podobnego. Dokonuje również porównania ciągów, czego POSIX [ nie robi (chociaż można sobie wyobrazić sposoby użycia do tego celu sort).
  • podkreślenie jako symbol zastępczy składni – jesteś Schemerem, @Giles? :]
  • @RubyTuesdayDONO Nie ' nie użyłem tutaj podkreślenia. Czy źle czytasz U + 2026 HORIZONTAL ELLIPSIS? Jeśli tak, spróbuj użyć większej czcionki.
  • @Giles – ok, tak, wygląda jak podkreślenie tylko ze względu na rozmiar mojej czcionki. dla mnie ” Schemat ” jest uzupełnieniem i ' nie przypomina elips kontra podkreślenie zmienia znaczenie i tak… nie ma potrzeby, by się nad tym przekonywać: /

Odpowiedź

Użyj nawiasów z cytaty:

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

Cudzysłowy uniemożliwiają bashowi interpretowanie nawiasów jako składni basha.

Komentarze

  • Nicolas ilustruje, ale nie wyjaśnia, że tokeny w wierszu poleceń expr muszą być oddzielone spacjami; więc; na przykład expr 3 "*" "(2" "+" "1)" nie będzie działać . (Przy okazji, prawdopodobnie nie musisz cytować +.)
  • Nawiasy to nie ' t słowa kluczowe, takie jak while i [[, mają ' ponownie składnię. Gdyby były słowami kluczowymi, nie byłyby ' zinterpretowane jako takie w argumentach poleceń. Potrzebujesz cudzysłowów, aby bash nie ' nie analizował ich, ale zamiast tego widział literał ciągu.

Odpowiedź

Jeśli masz bc ..

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

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *