Chcę reprezentować wiele takich warunków:
if [ ( $g -eq 1 -a "$c" = "123" ) -o ( $g -eq 2 -a "$c" = "456" ) ]
then
echo abc;
else
echo efg;
fi
ale kiedy wykonuję skrypt, pokazuje
syntax error at line 15: `[' unexpected,
gdzie wiersz 15 pokazuje, czy ...
Co jest nie tak z tym warunkiem? Chyba coś jest nie tak z ()
.
test
([
), a nie przez powłokę. Powłoka ocenia tylko status wyjścia[
.Odpowiedzi:
Klasyczna technika (metaznaki ucieczki):
Odwołuję się do
$g
podwójnych cudzysłowów; to ogólnie dobra praktyka. Ściśle, nawiasy nie są potrzebne, ponieważ pierwszeństwo-a
i-o
sprawia, że nawet bez nich poprawić.Zauważ, że operatory
-a
i-o
są częścią specyfikacji POSIXtest
, aka[
, głównie dla kompatybilności wstecznej (ponieważ na przykład były częściątest
wersji 7.IX UNIX), ale są wyraźnie oznaczone przez POSIX jako „przestarzałe”. Bash (zobacz wyrażeń warunkowych ) wydaje się wywłaszczyć klasyczne i POSIX znaczenia dla-a
i-o
z własnych operatorów alternatywnych, które przyjmują argumenty.Z pewną ostrożnością możesz użyć bardziej nowoczesnego
[[
operatora, ale pamiętaj, że wersje w Bash i Korn Shell (na przykład) nie muszą być identyczne.Przykład uruchomienia przy użyciu Bash 3.2.57 na Mac OS X:
Nie musisz cytować zmiennych,
[[
jak to robisz,[
ponieważ nie jest to osobne polecenie w taki sam sposób[
.Tak bym pomyślał. Istnieje jednak inna alternatywa, a mianowicie:
Rzeczywiście, jeśli przeczytasz wytyczne „przenośnej powłoki” dla
autoconf
narzędzia lub powiązanych pakietów, ta notacja - używanie „||
” i „&&
” - jest tym, co zalecają. Przypuszczam, że mógłbyś nawet posunąć się tak daleko:Tam, gdzie działania są tak trywialne jak echo, nie jest to złe. Gdy blok akcji, który ma być powtarzany, składa się z wielu wierszy, powtórzenie jest zbyt bolesne i preferowana jest jedna z wcześniejszych wersji - lub musisz zawinąć akcje w funkcję wywoływaną w różnych
then
blokach.źródło
-a
faktycznie ma wyższy priorytet niż-o
(w przeciwieństwie do&&
i||
w powłoce - jednak wewnątrzbash
[[ ... ]]
warunkowych ,&&
także ma wyższy priorytet niż||
). Jeśli chcesz uniknąć,-a
a-o
dla maksymalnej niezawodności i przenośności - co sugeruje sama strona podręcznika POSIX - możesz również użyć podpowłoki do grupowania:if ([ $g -eq 1 ] && [ "$c" = "123" ]) || ([ $g -eq 2 ] && [ "$c" = "456" ])
if test "$g" -eq 1 -a "$c" = "123" || test "$g" -eq 2 -a "$c" = "456"; then ...
&&
lub||
jest również preferowane, ponieważ bardziej przypomina warunki warunkowe w innych językach i pozwala na warunki zwarcia. Na przykład:if [ -n "${check_inodes}" ] && [ "$(stat -f %i "/foo/bar")" = "$(stat -f %i "/foo/baz")" ]
. Robiąc to w ten sposób, jeślicheck_inodes
jest pusty, unikasz dwóch wywołaństat
, podczas gdy większy, złożony warunek testowy musi przetworzyć wszystkie argumenty przed wykonaniem (co może również prowadzić do błędów, jeśli zapomnisz o tym zachowaniu).W Bash:
źródło
bash
. Nawiasem mówiąc: w tym konkretnym przypadku nawiasy nie są nawet potrzebne, ponieważ wewnętrzne[[ ... ]]
warunki warunkowe&&
faktycznie mają wyższy priorytet niż||
- w przeciwieństwie do zewnętrznych warunków warunkowych.if
/ i umieścićelse
kod pomiędzythen
ifi
wstawić funkcję, aby uniknąć jej powtórzenia. W bardzo prostych przypadkach można użyćcase
instrukcji z;&
przewrotem (w Bash 4).Działa
/bin/bash
następujące działanie:źródło
Uważaj, jeśli masz spacje w zmiennych łańcuchowych i sprawdzasz, czy istnieją. Pamiętaj o ich prawidłowym zacytowaniu.
źródło
źródło
{ ;}
można zamiast tego użyć.W bash do porównywania ciągów możesz użyć następującej techniki.
Przykład:
źródło
źródło
możesz też połączyć więcej niż 2 warunki:
źródło