Více logických operátorů, ((A || B) & & C) a “ chyba syntaxe poblíž neočekávaného tokenu ”

Pracuji s Bash 3 a snažím se tvoří podmíněný. V C / C ++ je to mrtvé jednoduché: ((A || B) && C). V Bashi se to nepovedlo (myslím, že autoři Gitu museli přispět tímto kódem, než se přesunuli k jiným snahám).

To nefunguje. Všimněte si, že <0 or 1> není řetězcový literál; znamená to 0 nebo 1 (obvykle pochází z grep -i).

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi 

Výsledkem bude:

line 322: syntax error near unexpected token `[[" 

Zkoušel jsem:

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi 

výsledkem je:

line 322: syntax error near unexpected token `[[" 

Část problému spočívá v tom, že výsledky hledání jsou triviální příklady, nikoli složitější příklady se složenými podmínkami.

Jak provedu jednoduché ((A || B) && C) v Bashi?


Jsem připraven jej jednoduše rozbalit a opakovat stejné příkazy v několika blocích:

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then ... elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then ... fi 

Odpověď

Syntaxe bash není jako C, i když je její malá část inspirována C. Nemůžete se jednoduše pokusit napsat kód C a očekávat, že bude fungovat.

Hlavním bodem prostředí je spouštění příkazů. Příkaz open-bracket [ je příkaz, který provede jediný test¹. Můžete jej dokonce napsat jako test (bez závěrečné závorky). Operátory || a && jsou operátory prostředí, kombinují příkazy , nikoli testy.

Takže když píšete

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ] 

, který je analyzován jako

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ] 

který je stejný jako

test [ "$A" -eq "0" || test "$B" -ne "0" ] && test "$C" -eq "0" 

Všimněte si nevyvážených závorek? Ano, to není dobré. Váš pokus se závorkami má stejný problém: podvržené závorky.

Syntaxí pro seskupování příkazů jsou složené závorky. Způsob, jakým jsou závorky analyzovány, vyžaduje před nimi kompletní příkaz, takže budete muset příkaz uvnitř závorek ukončit novým řádkem nebo středníkem.

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then … 

Tady „je alternativní způsob, kterým je použití dvojitých závorek. Na rozdíl od jednoduchých závorek jsou dvojité závorky speciální syntaxí prostředí. Oddělují podmíněné výrazy . V dvojitých závorkách můžete použít závorky a operátory jako && a ||. Vzhledem k tomu, že dvojité závorky jsou syntaxí prostředí, prostředí ví, že když jsou tyto operátory uvnitř závorek, jsou „součástí syntaxe podmíněného výrazu, nikoli součástí běžné syntaxe příkazu prostředí.

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then … 

Pokud jsou všechny vaše testy číselné, existuje ještě další způsob, který odděluje artihmetické výrazy . Aritmetické výrazy provádějí celočíselné výpočty se syntaxí podobnou písmenu C.

if (((A == 0 || B != 0) && C == 0)); then … 

Můžete najít moji bash závorku primer užitečný.

[ lze použít v obyčejném sh. [[ a (( jsou specifické pro bash (a ksh a zsh).

¹ Může také kombinovat více testů s booleovskými operátory, ale je to těžko použitelné a má to jemná úskalí, takže to nevysvětlím.

Komentáře

  • Díky Giles. Platí to pro Bash 2 až Bash 4? Potřebuji něco mírně přenositelného, ale Kusalananda zmínil, že některé věci, které jsem nedělal , jsou přenosné (znamená to, že to, co dělám, je není přenosný?). Zde mírně znamená Bash 2 až Bash 4.
  • @jww [[ … ]] byl přidán v bash 2.02. ((…)) byl přidán do bash 2.0.
  • @Giles – díky. Bash 2 je pro většinu pravděpodobně směšný. Je to kvůli naší správě a neochotě k opuštění starších platforem. Bash 2 a GCC 3 se objeví na našem testování Fedory 1. Starší platformu občas necháme jít, ale musí k tomu být důvody. ' Přihlaste se k odběru zásad opouštění softwaru Apple, Microsoft, Mozilla atd.
  • @jww Pochopte, prosím, že přednost || a && změna z [ na [[ a ((. Stejná přednost v [ (k určení pořadí vyhodnocení použijte závorky), ale & & má vyšší prioritu v [[ a (( než v || (jako v C).
  • @Roland Ne, závorky uvnitř [[ … ]] nebo $((…)) jsou jen pro seskupování.

Odpověď

Použijte [[:

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ... 

Pokud dáváte přednost [, funguje následující:

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ... 

Komentáře

  • Děkuji, Stephene. V mém případě jsem tedy použil váš první příklad … regex = ' ^ [0-9] + $ ' length = $ {#datearg} pokud! [[$ datearg = ~ $ regex & & $ length -eq 8]]; then echo " error: Not a number of lenth of 8 "; fi

Odpověď

Použijte operátor -o místo svého vnořené ||. Můžete také použít -a k nahrazení & &, pokud je to nutné ve vašich dalších prohlášeních .

 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true if [ "$A" -eq "0" -o "$B" -ne "0" ] && [ "$C" -eq "0" ]; then echo success;fi 

Komentáře

  • Děkuji. Narazil jsem na -a a -o, ale neexperimentoval jsem s nimi. Někdo na přetečení zásobníku řekl, aby se tomu vyhnul. Většinou jsem s nimi souhlasil, protože skript je při jejich používání méně čitelný.
  • … ale přenosnější.
  • @Kusalananda – děkuji za heads-upy týkající se přenositelnosti. Skript musí být spuštěn v systémech s Bash 2 až Bash 4. Bude na nich [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]] potíže?
  • Nebudou žádné problémy, pokud budete bash nebo jakýkoli jiný shell, který rozumí [[ ... ]].
  • Nevýhodou použití -a je, že to ' t zkrat, pokud je první výraz falešný. Pokud se tedy spoléháte na zkrat, abyste zabránili spuštění potenciálního fatálního druhého výrazu, nemůžete použít -a. Příklad: pastebin.com/zM77TXW1

Napsat komentář

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