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 let
wbudowanego basha:
$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9
Uwaga
Jak zauważył @ Stéphane Chazelas , bash
powinieneś używać ((...))
arytmetyki nad expr
lub let
dla 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 ksh
i 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ć expr
arytmetyki w nowoczesnych powłokach.
POSIX definiuje $((...))
operator ekspansji. Możesz więc używać tego we wszystkich powłokach zgodnych z POSIX ( sh
wszystkich współczesnych uniksowych lajków, dash, bash, yash, mksh, zsh, posh, ksh ...).
a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))
ksh
wprowadzono również let
wbudowane, 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 expr
oczywiście), ksh
wprowadzono 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.
let
i ((...))
są dostępne tylko w ksh
, zsh
i bash
. $((...))
Składni powinny być korzystna, jeśli potrzebny do przenoszenia innych powłok, expr
potrzebne 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 expr
wbudowaną (faktycznie połączoną test
), ale została później usunięta.
: $((a = a*2))
?
$((...))
takie jak zsh, ksh93 lub yash.
expr
jest poleceniem zewnętrznym, nie jest specjalną składnią powłoki. Dlatego jeśli chcesz expr
zobaczyć znaki specjalne powłoki, musisz chronić je przed analizą powłoki, cytując je. Ponadto expr
wymaga 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 expr
zamiast 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 expr
oferuje kilka funkcji manipulacji ciągami. Te także są uwzględniane przez funkcje powłok POSIX, z wyjątkiem jednego: expr STRING : REGEXP
testuje, 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 - expr
jest 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 expr
kiedykolwiek istniał. Użyj arytmetyki powłoki.
expr foo : '\(.\)'
wykonuje również ekstrakcję tekstu. bash
„s BASH_REMATCH
osią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.
expr
wierszu 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ć +
.)
while
i [[
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.