expr wydaje się nie lubić nawiasów (używanych w matematyce do jawnego priorytetu operatora):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
Jak wyrazić priorytet operatora w bash?
expr wydaje się nie lubić nawiasów (używanych w matematyce do jawnego priorytetu operatora):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
Jak wyrazić priorytet operatora w bash?
Odpowiedzi:
Innym sposobem na użycie letwbudowanego basha:
$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9
Uwaga
Jak zauważył @ Stéphane Chazelas , bashpowinieneś używać ((...))arytmetyki nad exprlub letdla czytelności.
Aby uzyskać przenośność, użyj odpowiedzi$((...)) typu @Bernhard .
let. Nie jest bardziej standardowy ani przenośny niż (( a = 3 * (2 + 1) ))(oba pochodzą z kshi są dostępne tylko w ksh, bash i zsh) i jest mniej czytelny lub łatwy do cytowania. Użyj, a=$((3 * (2 + 1)))aby być przenośnym.
((a = 3 * (2 + 1) )), jedna dla przenośności a=$((3 * (2 + 1)))), więc nie jest to notatka przeciwko tobie lub twojej odpowiedzi, ale przeciwko temu, że jest wybraną odpowiedzią i najlepszy strzelec.
a=1 $[a+2]lub a=1 b=2 $[a+b]. Czy ich powodem jest unikanie tej składni?
Zamiast tego możesz użyć rozszerzenia arytmetycznego.
echo "$(( 3 * ( 2 + 1 ) ))"
9
Moim osobistym zdaniem wygląda to nieco ładniej niż używanie expr.
Od man bash
Rozwinięcie arytmetyczne Rozwinięcie arytmetyczne pozwala na ocenę wyrażenia arytmetycznego i podstawienie wyniku. Format rozszerzania arytmetycznego to:
$((expression))Wyrażenie jest traktowane tak, jakby znajdowało się w podwójnych cudzysłowach, ale podwójne cudzysłowy w nawiasach nie są traktowane specjalnie. Wszystkie tokeny w wyrażeniu podlegają interpretacji parametrów, interpretacji ciągów, zastępowaniu poleceń i usuwaniu cytatów. Rozszerzenia arytmetyczne mogą być zagnieżdżone.
Ocena przeprowadzana jest zgodnie z zasadami wymienionymi poniżej w części OCENA ARTYMETYCZNA. Jeśli wyrażenie jest niepoprawne, bash wypisuje komunikat wskazujący błąd i nie występuje podstawienie.
Nie ma powodu, aby używać exprarytmetyki w nowoczesnych powłokach.
POSIX definiuje $((...))operator ekspansji. Możesz więc używać tego we wszystkich powłokach zgodnych z POSIX ( shwszystkich współczesnych uniksowych lajków, dash, bash, yash, mksh, zsh, posh, ksh ...).
a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))
kshwprowadzono również letwbudowane, które jest przekazywane tego samego rodzaju wyrażenie arytmetyczne, nie rozwija się w coś, ale zwraca status wyjścia na podstawie tego, czy wyrażenie jest interpretowane na 0, czy nie, jak w expr:
if let 'a = 3 * (2 + 1)'; then
echo "$a is non-zero"
fi
Ponieważ jednak cytowanie sprawia, że jest to niewygodne i mało czytelne (nie w takim samym stopniu jak exproczywiście), kshwprowadzono także ((...))alternatywną formę:
if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then
echo "$a is non-zero and 3 > 1"
fi
((a+=2))
który jest o wiele bardziej czytelny i powinien być używany zamiast tego.
leti ((...))są dostępne tylko w ksh, zshi bash. $((...))Składni powinny być korzystna, jeśli potrzebny do przenoszenia innych powłok, exprpotrzebne jest tylko do wstępnego POSIX Bourne powłokach (zazwyczaj Bourne powłoki lub wczesne wersje Almquist Shell).
Na froncie innym niż Bourne znajduje się kilka pocisków z wbudowanym operatorem arytmetycznym:
csh/ tcsh(właściwie pierwsza powłoka uniksowa z wbudowaną analizą arytmetyczną):
@ a = 3 * (2 + 1)akanga(na podstawie rc)
a = $:'3 * (2 + 1)'jak napisano w historii, oryginalna wersja powłoki Almquist, opublikowana na usenet w 1989 roku, miała exprwbudowaną (faktycznie połączoną test), ale została później usunięta.
: $((a = a*2))?
$((...))takie jak zsh, ksh93 lub yash.
exprjest poleceniem zewnętrznym, nie jest specjalną składnią powłoki. Dlatego jeśli chcesz exprzobaczyć znaki specjalne powłoki, musisz chronić je przed analizą powłoki, cytując je. Ponadto exprwymaga podania każdej liczby i operatora jako osobnego parametru. A zatem:
expr 3 \* \( 2 + 1 \)
O ile nie pracujesz na antycznym systemie uniksowym z lat 70. lub 80. XX wieku, nie ma zbyt wiele powodów, aby z niego korzystać expr. W dawnych czasach powłoki nie miały wbudowanego sposobu wykonywania arytmetyki, a exprzamiast tego trzeba było wywołać narzędzie. Wszystkie powłoki POSIX mają wbudowaną arytmetykę poprzez arytmetyczną składnię rozszerzającą .
echo "$((3 * (2 + 1)))"
Konstrukt $((…))rozwija się do wyniku wyrażenia arytmetycznego (zapisanego dziesiętnie). Bash, podobnie jak większość powłok, obsługuje tylko liczbę całkowitą arytmetyczną modulo 2 64 (lub modulo 2 32 dla starszych wersji basha i niektórych innych powłok na maszynach 32-bitowych).
Bash oferuje dodatkową wygodną składnię, gdy chcesz wykonać przypisania lub sprawdzić, czy wyrażenie ma wartość 0, ale nie przejmuj 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 exproferuje kilka funkcji manipulacji ciągami. Te także są uwzględniane przez funkcje powłok POSIX, z wyjątkiem jednego: expr STRING : REGEXPtestuje, czy łańcuch pasuje do określonego wyrażenia regularnego. Powłoka POSIX nie może tego zrobić bez zewnętrznych narzędzi, ale bash może [[ STRING =~ REGEXP ]](z inną składnią wyrażenia regularnego - exprjest klasycznym narzędziem i używa BRE, bash używa ERE).
O ile nie zajmujesz się skryptami działającymi na 20-letnich systemach, nie musisz wiedzieć, że exprkiedykolwiek istniał. Użyj arytmetyki powłoki.
expr foo : '\(.\)'wykonuje również ekstrakcję tekstu. bash„s BASH_REMATCHosiąga coś podobnego. Dokonuje również porównania ciągów, czego [nie robi POSIX (choć można sobie wyobrazić, jak tego użyć sort).
Używaj nawiasów z cytatami:
expr 3 '*' '(' 2 '+' 1 ')'
9
Cytaty uniemożliwiają bashowi zinterpretowanie nawiasu jako składni bash.
exprwierszu poleceń muszą być oddzielone spacjami; więc; na przykład expr 3 "*" "(2" "+" "1)" nie będzie działać . (Ponadto, BTW, prawdopodobnie nie musisz cytować +.)
whilei [[są składnią. Gdyby były słowami kluczowymi, nie byłyby interpretowane jako takie w argumentach poleceń. Potrzebujesz cudzysłowów, aby bash ich nie analizował, a zamiast tego widział dosłowny ciąg znaków.