Závorka v expr aritmetice: 3 * (2 + 1)

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

  • +1 Ještě čitelnější! Zveřejnil jsem svou otázku + odpověď jen v domnění, že by to bylo užitečné pro mé kolegy z uživatelů Linuxu, ale nyní získávám mnoho výhod z ostatních odpovědí 🙂
  • Tam ‚ není důvod používat let. Není to ‚ o nic standardnější ani přenosnější než (( a = 3 * (2 + 1) )) (oba pocházejí z ksh a jsou k dispozici pouze v ksh, bash a zsh) a je ‚ méně čitelný nebo snadno citovatelný. Použijte a=$((3 * (2 + 1))) k přenosnosti.
  • Ne ‚ to neříkám ‚ s špatně, ‚ jen říkám, že by se to nemělo používat, protože existují lepší alternativy (jedna pro čitelnost ((a = 3 * (2 + 1) )), jedna pro přenositelnost a=$((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 .
  • @St é phaneChazelas: Aktualizována moje odpověď!
  • Vždy jsem používal a=1 $[a+2] nebo a=1 b=2 $[a+b]. Je jejich důvod se této syntaxi vyhnout?

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 s test), 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 ‚ s BASH_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žít sort).
  • 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říklad expr 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 

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *