Jaka jest składnia złożonego warunku w powłoce?


11

Jeśli chcesz wyrazić następujący test w powłoce (sh):

if ( a == 1 && ( b == 1 || b == 2 )) { ... }

Do tej pory najlepsze, co udało mi się napisać, to:

if [[ $a -eq 1 ]]; then
  if [[ $b -eq 1 || $b -eq 2 ]]; then
     ...
  fi
fi

Nie wiem jak połączyć && i || z właściwym pierwszeństwem. Googling nie dał mi żadnej odpowiedzi (tutoriale podają tylko podstawowe przykłady, jeśli takie istnieją)

Jaka jest składnia, aby połączyć te dwa, jeśli w jeden?


1
Czy jest jakiś powód, aby nie używać ksh? Wówczas początkowy kod wymagałby tylko jednej pary nawiasów:if (( a == 1 && ( b == 1 || b == 2 ))); then :; fi
manatwork

Odpowiedzi:


15

Pamiętaj, że [[ ]]nie ma go w Bourne ani POSIX sh. Aby uzyskać prawdziwą shskładnię, można to zrobić na kilka sposobów.

Używanie tylko jednej [ ]pary

if [ 1 -eq "$a" -a \( 1 -eq "$b" -o 2 -eq "$b" \) ]; then
    # ...
fi

lub Unikanie POSIX -ai -oopcji 1

if [ 1 -eq "$a" ] && { [ 1 -eq "$b" ] || [ 2 -eq "$b" ]; }; then
    # ...
fi

1 Jednym z powodów, dla uniknięcia -ai -ojest maksymalna mobilność - nie wszystkie testlub [implementacje mogą obsługiwać więcej niż 4 argumenty, co jest dokładnie to, co masz, jeśli łańcuch wyrażeń z -ai -oa \( \).


Moje skrypty mają #! / bin / sh shebang, a domyślną powłoką jest ksh . Dlaczego nie byłby używany?
Offirmo,

2
@Offirmo Jeśli zadeklarujesz swój skrypt jako /bin/sh, pisanie go przy użyciu funkcji, których nie ma, jest nieprawidłowe sh. Powinieneś zdawać sobie sprawę, że kshto NIE jest sh, ale raczej nadzbiór sh. Jeśli zabierzesz swój skrypt, kshale zadeklarowany jako, shdo systemu, w którym shnie ma dowiązania symbolicznego ksh, może się on zepsuć. Możesz uniknąć tego problemu, upewniając się, że skrypt pasuje do deklaracji.
jw013,

Myślałem, że ustawienie / bin / sh jako shebang spowoduje, że moje skrypty będą wywoływane przez / bin / sh . Czy masz na myśli to, że moja domyślna powłoka (ksh) ignoruje shebang i interpretuje go bezpośrednio?
Offirmo,

@Offirmo Masz rację: szereg /bin/shwywoła /bin/sh. Problem /bin/shnie jest akceptowany [[. Nie możesz użyć [[ani użyć powłoki, która akceptuje [[, np. kshJako twój shebang.
jw013

2
Problemem nie jest to, że -a/ -onie są obsługiwane przez niektóre implementacje, ale to, że nie jest wiarygodne w przypadku arbitralnych argumentów. Podobnie [ "$a" = "$b" -o "$b" = "$c" ]mogłoby się nie powieść dla wartości $apodobnych !przy wielu [implementacjach.
Stéphane Chazelas

2

Wypróbowałem trochę składni i znalazłem to

if [[ $a -eq 1 ]] && [[ $b -eq 1 || $b -eq 2 ]]; then
 ...
fi

działa.


1
działa to dla wersji bash powyżej 4.
Nikhil Mulley


0

Właściwy sposób to zrobić za pomocą samego shell:

if test 1 -eq "$a" && test 1 -eq "$b" -o 2 -eq "$b"; then 
    ...
fi

Wyjaśnienie:

testtutaj służy jako nawias i -ologiczny lub. Jeśli logiczny i wewnątrz „nawiasu” użyłbyś -a.

Więcej na ten temat można znaleźć tutaj

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.