Wiele operatorów logicznych ((A || B) & & C) i “ błąd składni w pobliżu nieoczekiwanego tokena ”

Pracuję z Bash 3 i próbuję tworzą warunek. W C / C ++ jest to banalnie proste: ((A || B) && C). W Bash okazuje się, że tak nie jest (myślę, że autorzy Git musieli wnieść ten kod, zanim przeszli do innych przedsięwzięć).

To nie działa. Zauważ, że <0 or 1> nie jest literałem ciągu; oznacza 0 lub 1 (generalnie pochodzi 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 

Wynik:

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

Następnie próbowałem:

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

skutkuje:

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

Częścią problemu jest to, że wyniki wyszukiwania są trywialnymi przykładami, a nie bardziej złożonymi przykładami ze złożonymi warunkami warunkowymi.

Jak wykonać proste ((A || B) && C) w Bash?


Jestem gotowy, aby go po prostu rozwinąć i powtórzyć te same polecenia w wielu blokach:

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 

Odpowiedź

Składnia bash nie jest podobna do C, nawet jeśli niewielka jego część jest inspirowana przez C. Nie możesz po prostu spróbować napisać kodu w C i oczekiwać, że zadziała.

Głównym celem powłoki jest wykonywanie poleceń. Polecenie otwartego nawiasu klamrowego [ to polecenie, które wykonuje pojedynczy test¹. Możesz nawet zapisać go jako test (bez końcowego nawiasu zamykającego). Operatory || i && są operatorami powłoki, łączą polecenia , a nie testy.

Więc kiedy piszesz

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

jest to analizowane jako

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

które jest tym samym, co

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

Zwróć uwagę na niezrównoważone nawiasy? Tak, to nie jest dobre. Twoja próba użycia nawiasów ma ten sam problem: fałszywe nawiasy.

Składnia grupowania poleceń to nawiasy. Sposób, w jaki są analizowane nawiasy klamrowe, wymaga pełnego polecenia przed nimi, więc „będziesz musiał zakończyć polecenie wewnątrz nawiasów znakiem nowej linii lub średnika.

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

Tam to alternatywny sposób, który polega na użyciu podwójnych nawiasów. W przeciwieństwie do nawiasów pojedynczych, nawiasy podwójne są specjalną składnią powłoki. Odgraniczają wyrażenia warunkowe . W podwójnych nawiasach można używać nawiasów i operatorów, takich jak && i ||. Ponieważ podwójne nawiasy są składnią powłoki, powłoka wie, że gdy te operatory znajdują się w nawiasach, „stanowią część składni wyrażenia warunkowego, a nie zwykłej składni poleceń powłoki.

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

Jeśli wszystkie twoje testy są numeryczne, istnieje jeszcze inny sposób, który ogranicza wyrażenia artystyczne . Wyrażenia arytmetyczne wykonują obliczenia na liczbach całkowitych przy użyciu składni bardzo podobnej do języka C.

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

Możesz znaleźć mój nawias bash primer przydatne.

[ może być używany w zwykłym sh. [[ i (( są specyficzne dla bash (oraz ksh i zsh).

¹ Może również łączenie wielu testów z operatorami logicznymi, ale jest to niewygodne w użyciu i ma subtelne pułapki, więc nie będę tego wyjaśniał.

Komentarze

  • Dzięki Giles. Czy to dotyczy od Bash 2 do Bash 4? Potrzebuję czegoś umiarkowanie przenośnego, ale Kusalananda wspomniał, że niektóre rzeczy, których nie robiłem, są przenośne (czy to oznacza > nie przenośny?). Tutaj łagodnie oznacza od Bash 2 do Bash 4.
  • @jww [[ … ]] został dodany w bash 2.02. ((…)) został dodany w bashu 2.0.
  • @Giles – dzięki. Bash 2 jest prawdopodobnie śmieszny dla większości. Wynika to z naszego zarządzania i niechęci porzucić starsze platformy. Bash 2 i GCC 3 pojawiają się w naszych testach Fedory 1. Czasami pozwalamy starszej platformie działać, ale muszą być ku temu powody. Nie ' t subskrybuj zasady firmy Apple, Microsoft, Mozilla itp. dotyczące porzucenia oprogramowania.
  • @jww Proszę zrozumieć, że pierwszeństwo || i && zmień z [ na [[ i ((. Równe pierwszeństwo w [ (użyj nawiasów, aby kontrolować kolejność oceny), ale & & ma wyższy priorytet w [[ i (( niż || (jak w C).
  • @Roland Nie, nawiasy wewnątrz [[ … ]] lub $((…)) służą tylko do grupowania.

Odpowiedź

Użyj [[:

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

Jeśli wolisz [, działa to:

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

Komentarze

  • Dziękuję, Stephen. W moim przypadku użyłem twojego pierwszego przykładu w ten sposób … regex = ' ^ [0-9] + $ ' length = $ {#datearg} jeśli! [[$ datearg = ~ $ regex & & $ length -eq 8]]; następnie echo " błąd: To nie jest liczba dł. z 8 "; fi

Odpowiedź

Użyj operatora -o zamiast swojego zagnieżdżone ||. Możesz także użyć -a, aby zastąpić & &, jeśli jest to potrzebne w innych wyciągach .

 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 

Komentarze

  • Dziękujemy. Natrafiłem na -a i -o, ale nie eksperymentowałem z nimi. Ktoś na Stack Overflow powiedział, żeby tego unikać. W większości się z nimi zgadzałem, ponieważ skrypt jest mniej czytelny przy ich użyciu.
  • … ale bardziej przenośny.
  • @Kusalananda – Dzięki za ostrzeżenia o przenośności. Skrypt musi działać na systemach z Bash 2 do Bash 4. Czy [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]] będą miały z nimi problemy?
  • Nie będzie żadnych problemów, o ile będziesz bash lub jakąkolwiek inną powłokę, która rozumie [[ ... ]].
  • Wadą użycia -a jest to, że nie ' t zwarcie, jeśli pierwsze wyrażenie jest fałszywe. Więc jeśli polegasz na zwarciu, aby zapobiec uruchomieniu potencjalnie fatalnego drugiego wyrażenia, nie możesz użyć -a. Przykład: pastebin.com/zM77TXW1

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *