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
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
[[ … ]]
został dodany w bash 2.02.((…))
został dodany w bashu 2.0.||
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).[[ … ]]
lub$((…))
służą tylko do grupowania.