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
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 podstawierc
)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 ztest
), 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
' sBASH_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 celusort
). - 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ładexpr 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
let
. ' nie jest bardziej standardowe ani przenośne niż(( a = 3 * (2 + 1) ))
(oba pochodzą zksh
i są dostępne tylko w ksh, bash i zsh) i ' są mniej czytelne lub łatwe do zacytowania. Użyja=$((3 * (2 + 1)))
jako przenośnego.((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 .a=1 $[a+2]
luba=1 b=2 $[a+b]
. Czy ich powód, aby unikać tej składni?