expr
zřejmě nemá rád závorky (používá se v matematice k explicitní prioritě operátora):
expr 3 * (2 + 1) bash: syntax error near unexpected token `("
Jak vyjádřit prioritu operátora v bash?
Odpověď
Další způsob použití let
integrovaného bash:
$ let a="3 * (2 + 1)" $ printf "%s\n" "$a" 9
Poznámka
Jak @ Stéphane Chazelas zdůraznil , v bash
byste měli použít ((...))
k provádění aritmetiky nad expr
nebo let
kvůli čitelnosti.
Pro přenositelnost použijte $((...))
jako @Bernhard answer .
Komentáře
Odpovědět
Místo toho můžete použít aritmetickou expanzi.
echo "$(( 3 * ( 2 + 1 ) ))" 9
Podle mého osobního názoru to vypadá o něco hezčí než použití expr
.
Od man bash
Aritmetické rozšíření Aritmetická expanze umožňuje vyhodnocení aritmetického výrazu a nahrazení výsledku. Formát pro aritmetické rozšíření je:
$((expression))
S výrazem se zachází, jako by byl v uvozovkách, ale s uvozovkami uvnitř závorek není zacházeno zvlášť. Všechny tokeny ve výrazu procházejí rozšiřováním parametrů, rozšiřováním řetězců, nahrazováním příkazů a odstraňováním nabídek. Aritmetické expanze mohou být vnořeny.
Hodnocení se provádí podle pravidel uvedených níže v části ARITMETICKÉ HODNOCENÍ. Pokud je výraz neplatný, bash vytiskne zprávu označující selhání a nedojde k žádné záměně.
Komentáře
- Kromě čitelnosti také nevyžaduje ‚ t rozvětvení dalšího procesu k provedení aritmetiky; to ‚ s zpracovává samotný shell.
- Všimněte si, že v skořápkách POSIX je ‚ podléhat slovu rozdělení, takže ‚ je dobrým zvykem citovat to v kontextech seznamu.
- Když to zkusím v prostředí bash, dostanu ‚ Název nelegální proměnné. “
odpověď
Není důvod používat expr
pro aritmetiku v moderních skořápkách.
POSIX definuje $((...))
operátor expanze. Můžete jej tedy použít ve všech skořápkách kompatibilních s POSIXem (sh
všech moderních unixových rád, dash, bash, yash, mksh, zsh, posh, ksh … ).
a=$(( 3 * (2 + 1) )) a=$((3*(2+1)))
ksh
také představil let
vestavěný je předán stejný druh aritmetického výrazu, nerozbalí se do něčeho, ale vrátí stav ukončení podle toho, zda je výraz vyřešen es to 0 or not, like in expr
:
if let "a = 3 * (2 + 1)"; then echo "$a is non-zero" fi
Vzhledem k tomu, že citace to dělá trapným a ne velmi čitelný (samozřejmě ne ve stejné míře jako expr
), ksh
také představil ((...))
alternativní forma:
if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then echo "$a is non-zero and 3 > 1" fi ((a+=2))
, která je mnohem čitelnější a měla by se místo toho použít.
let
a ((...))
jsou k dispozici pouze v ksh
, zsh
a bash
.Syntaxe $((...))
by měla být upřednostňována, pokud je potřeba přenositelnost na jiné skořápky, expr
je potřeba pouze pro pre-POSIX skořápky typu Bourne (obvykle Bourneův shell nebo dřívější verze Almquistova shellu).
Na frontě, která není Bourne, existuje několik shellů s integrovaným aritmetickým operátorem:
-
csh
/tcsh
(vlastně první unixový shell s integrovaným aritmetickým vyhodnocením):@ a = 3 * (2 + 1)
-
akanga
(na základěrc
)a = $:"3 * (2 + 1)"
-
jako historická poznámka měla původní verze almquistského shellu, jak byla zveřejněna na síti usenet v roce 1989,
expr
builtin (ve skutečnosti sloučeno stest
), ale později to bylo odstraněno.
Komentáře
- Každý den se od tebe učím něco nového, St é phane. Velmi si vážím vašich znalostí prostředí POSIX!
- Co třeba
: $((a = a*2))
? - Co když mám plovoucí desetinnou čárku? Můj výraz je a = $ ((-14 + 0,2 * (1 + 2 + 3))). Chybový token je “ .2 * (1 + 2 + 3) “
- @Blaise, pak vy ‚ d potřebují prostředí, které podporuje plovoucí body v
$((...))
jako zsh, ksh93 nebo yash.
Odpověď
expr
je externí příkaz, nejedná se o speciální syntaxi prostředí. Pokud tedy chcete, aby expr
viděl speciální znaky prostředí, musíte je chránit před analýzou prostředí jejich citací. expr
navíc vyžaduje, aby každé číslo a operátor byly předány jako samostatný parametr. Tedy:
expr 3 \* \( 2 + 1 \)
Pokud nepracujete na starožitném unixovém systému ze 70. nebo 80. let, je velmi málo důvodů používat expr
. Za starých časů neměly mušle vestavěný způsob provádění aritmetiky a místo toho jste museli volat nástroj expr
. Všechny skořápky POSIX mají zabudovanou aritmetiku pomocí syntaxe aritmetické expanze .
echo "$((3 * (2 + 1)))"
The konstrukce $((…))
se rozšíří na výsledek aritmetického výrazu (zapsaného v desítkové soustavě). Bash, stejně jako většina skořápek, podporuje pouze celé číslo aritmetické modulo 2 64 (nebo modulo 2 32 pro starší verze bash a některé další skořápky na 32bitových počítačích).
Bash nabízí další pohodlnou syntaxi , pokud chcete provést přiřazení nebo otestovat, zda je výraz 0, ale nezáleží na výsledku. Tento konstrukt existuje také v ksh a zsh, ale ne v obyčejném sh.
((x = 3 * (2+1))) echo "$x" if ((x > 3)); then …
Kromě celočíselné aritmetiky expr
nabízí několik funkcí manipulace s řetězci. I tyto jsou zahrnuty do funkcí skořápek POSIX, kromě jedné: expr STRING : REGEXP
testuje, zda řetězec odpovídá zadanému regexp. Prostředí POSIX to nemůže udělat bez externí nástroje, ale bash může s [[ STRING =~ REGEXP ]]
(s jinou syntaxí regexp – expr
je klasický nástroj a používá BRE, bash používá ERE).
Pokud nepoužíváte skripty které běží na 20 let starých systémech, nemusíte vědět, že expr
kdy existoval. Použijte aritmetiku prostředí.
Komentáře
-
expr foo : '\(.\)'
také provádí extrakci textu.bash
‚ sBASH_REMATCH
dosahuje něčeho podobného. Rovněž provádí porovnání řetězců, což POSIX[
nedělá (i když by se daly představit způsoby, jak k tomu použítsort
). - podtržítko jako zástupný symbol syntaxe — jste Schemer, @Giles? :]
- @RubyTuesdayDONO Nepoužíval jsem ‚ podtržítko. Chybně čtete HORIZONTÁLNÍ Elipsu U + 2026? Pokud ano, zkuste použít větší písmo.
- @Giles – dobře, ano, vypadá to jen jako podtržítko kvůli mé velikosti písma. pro mě je “ Schemer “ doplňkem a ‚ to není jako elipsa versus podtržítko stejně mění význam … není třeba se nad tím chraptit: /
Odpovědět
Použijte závorky s citace:
expr 3 "*" "(" 2 "+" 1 ")" 9
Citáty zabraňují bash interpretovat závorky jako syntaxi bash.
Komentáře
- Co Nicolas ilustruje, ale nevysvětluje, je to, že tokeny v příkazovém řádku
expr
musí být odděleny mezerami; tak; napříkladexpr 3 "*" "(2" "+" "1)"
nebude fungovat . (BTW, pravděpodobně nebudete muset citovat+
.) - Závorky neobsahují ‚ klíčová slova jako
while
a[[
, ‚ jsou syntaxe. Pokud by to byla klíčová slova, nebyla by ‚ interpretována jako taková v argumentech příkazů. Potřebujete uvozovky, aby je bash ‚ neabsolvoval, ale místo toho viděl řetězcový literál.
Odpovědět
Pokud máte bc ..
echo "3 * (2 + 1)"|bc 9
let
. Není to ‚ o nic standardnější ani přenosnější než(( a = 3 * (2 + 1) ))
(oba pocházejí zksh
a jsou k dispozici pouze v ksh, bash a zsh) a je ‚ méně čitelný nebo snadno citovatelný. Použijtea=$((3 * (2 + 1)))
k přenosnosti.((a = 3 * (2 + 1) ))
, jedna pro přenositelnosta=$((3 * (2 + 1)))
), takže ‚ to není poznámka proti vám nebo vaší odpovědi, ale proti tomu, aby byla vybranou odpovědí a nejlepším střelcem .a=1 $[a+2]
neboa=1 b=2 $[a+b]
. Je jejich důvod se této syntaxi vyhnout?