Instrukcja Bash if z wieloma warunkami zgłasza błąd

165

Próbuję napisać skrypt, który będzie sprawdzał dwie flagi błędów i w przypadku zmiany jednej flagi (lub obu) pojawi się echo - wystąpił błąd. Mój skrypt:

my_error_flag=0
my_error_flag_o=0
do something.....
if [[ "$my_error_flag"=="1" || "$my_error_flag_o"=="2" ] || [ "$my_error_flag"="1" &&     "$my_error_flag_o"="2" ]]; then
    echo "$my_error_flag"
else
    echo "no flag"
fi

Zasadniczo powinno być coś w tym:

if ((a=1 or b=2) or (a=1 and b=2))
  then
     display error
else
     no error
fi

Otrzymuję błąd:

 line 26: conditional binary operator expected
 line 26: syntax error near `]'
 line 26: `if [[ "$my_error_flag"=="1" || "$my_error_flag_o"=="2" ] || [ "$my_error_flag"="1" && "$my_error_flag_o"="2" ]]; then'

Czy moje nawiasy są pomieszane?

Po prostu ja
źródło
2
Użyj nawiasów - ()
AlikElzin-kilaka,
Zobacz także stackoverflow.com/questions/3826425/…
tripleee,
3
Logicznie rzecz biorąc, a==1 or b==2obejmuje już przypadek, w którym a==1 and b==2. Testowanie osobno jest tutaj całkowicie zbędne.
tripleee

Odpowiedzi:

249

Użyj -a(dla i) i -o(dla lub) operacji.

tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html

Aktualizacja

Właściwie można nadal korzystać &&i ||przy -eqpracy. Więc twój skrypt wyglądałby tak:

my_error_flag=1
my_error_flag_o=1
if [ $my_error_flag -eq 1 ] ||  [ $my_error_flag_o -eq 2 ] || ([ $my_error_flag -eq 1 ] && [ $my_error_flag_o -eq 2 ]); then
      echo "$my_error_flag"
else
    echo "no flag"
fi

Chociaż w twoim przypadku możesz odrzucić ostatnie dwa wyrażenia i po prostu trzymać się jednego lub takiej operacji:

my_error_flag=1
my_error_flag_o=1
if [ $my_error_flag -eq 1 ] ||  [ $my_error_flag_o -eq 2 ]; then
      echo "$my_error_flag"
else
    echo "no flag"
fi
mkhatib
źródło
3
@Simply_Me: Nie, logiczne OR jest prawdziwe, jeśli jeden lub oba jego operandy są prawdziwe. Myślisz o „wyłączności” lub (XOR), co jest prawdą, jeśli dokładnie jeden z jego argumentów jest prawdziwy. (W rzeczywistości istnieją wersje XOR, które działają na więcej niż 2 operandach, w takim przypadku jest to prawdą, jeśli nieparzysta liczba operandów jest prawdziwa.)
Gordon Davisson
4
BTW, problemy w oryginalnym kodzie obejmują używanie [i ]do grupowania (nie robią tego) i nieumieszczanie spacji wokół operatora (np. "$my_error_flag"="1"), Co uniemożliwia powłoce rozpoznanie go jako operatora w ogóle. Przeczytaj BashFAQ # 17 (na temat grupowania) i # 31 (na temat różnicy między różnymi typami wyrażeń testowych) . Właściwie w tym przypadku byłoby jeszcze łatwiej użyć wyrażenia arytmetycznego .
Gordon Davisson
7
-ai -osą uważane za przestarzałe w specyfikacji POSIX ; użyj oddzielnych testów połączonych z ||jak w aktualizacji.
chepner
1
Nie ma potrzeby grupowania za pomocą podpowłok, normalnie grupowanie przy użyciu {}powinno być również możliwe.
phk
1
aby dodać do powyższego komentarza phk, () uruchamia podpowłoki w bashu, które mogą mieć różnego rodzaju subtelne [prawdopodobnie niepożądane] efekty.
brett
70

Możesz użyć słowa kluczowego [[lub ((. Gdy używasz [[słów kluczowych, masz operatorom korzystanie strunowych, takich jak -eq, -lt. Myślę, że ((jest najbardziej preferowany do arytmetyki, ponieważ możesz bezpośrednio używać operatorów, takich jak ==, <i >.

Korzystanie [[operator

a=$1
b=$2
if [[ a -eq 1 || b -eq 2 ]] || [[ a -eq 3 && b -eq 4 ]]
then
     echo "Error"
else
     echo "No Error"
fi

Korzystanie ((operator

a=$1
b=$2
if (( a == 1 || b == 2 )) || (( a == 3 && b == 4 ))
then
     echo "Error"
else
     echo "No Error"
fi

Nie używaj -aani -ooperatorów, ponieważ nie jest przenośny.

Fizer Khan
źródło
8

Spróbuj śledzić

if ([ $dateR -ge 234 ] && [ $dateR -lt 238 ]) || ([ $dateR -ge 834 ] && [ $dateR -lt 838 ]) || ([ $dateR -ge 1434 ] && [ $dateR -lt 1438 ]) || ([ $dateR -ge 2034 ] && [ $dateR -lt 2038 ]) ;
then
    echo "WORKING"
else
    echo "Out of range!"
Manash Nath
źródło
2
( ... )tworzy podpowłoki - duży wpływ na wydajność bez żadnych korzyści.
Charles Duffy
4
Służy { ...; }do grupowania bez tworzenia podpowłoki.
Charles Duffy
1

Możesz czerpać inspirację, czytając entrypoint.sh skrypt napisany przez autorów z MySQL, który sprawdza, czy określone zmienne zostały ustawione.

Jak pokazuje skrypt, możesz je potokować -anp .:

if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
    ...
fi
Daniel Andrei Mincă
źródło
1
-ajest oznaczony jako przestarzały w aktualnej wersji teststandardu POSIX ; zobacz OBznaczniki na pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html . Użyj, [ -z "$FOO" ] && [ -z "$BAR" ]aby uzyskać bardziej niezawodny kod.
Charles Duffy