Mylące użycie && i || operatorzy

92

Przeglądałem /etc/rc.d/init.d/sendmailplik (wiem, że rzadko się go używa, ale przygotowuję się do egzaminu) i trochę się zdezorientowałem co &&do ||operatorów. Przeczytałem, gdzie można ich używać w instrukcjach takich jak:

if [ test1 ] && [ test2 ]; then
     echo "both tests are true"
elif [ test1 ] || [ test2 ]; then
     echo "one test is true"
fi

Jednak ten skrypt wyświetla instrukcje jednowierszowe, takie jak:

[ -z "$SMQUEUE" ] && SMQUEUE="QUEUE"
[ -f /usr/sbin/sendmail ] || exit 0

Wydaje się, że używają one operatorów &&i ||do wywoływania odpowiedzi na podstawie testów, ale nie byłem w stanie wykopać dokumentacji dotyczącej tego konkretnego zastosowania tych operatorów. Czy ktoś może wyjaśnić, co robią w tym konkretnym kontekście?

josh-cain
źródło

Odpowiedzi:

140

Prawa strona &&zostanie oceniona tylko wtedy, gdy stan wyjścia z lewej strony będzie wynosił zero (tj. Prawda). ||jest odwrotnie: ocenia prawą stronę tylko wtedy, gdy status wyjścia z lewej strony jest niezerowy (tj. fałszywy).

Możesz uznać [ ... ]za program o wartości zwracanej. Jeśli test w środku ma wartość true, zwraca zero; w przeciwnym razie zwraca wartość niezerową.

Przykłady:

$ false && echo howdy!

$ true && echo howdy!
howdy!
$ true || echo howdy!

$ false || echo howdy!
howdy!

Dodatkowe uwagi:

Jeśli to zrobisz which [, możesz zauważyć, że [tak naprawdę oznacza to program! Jednak zwykle nie jest to ten, który działa w skryptach; biegnij, type [aby zobaczyć, co się właściwie uruchamia. Jeśli wan spróbować za pomocą programu, wystarczy podać pełną ścieżkę tak: /bin/[ 1 = 1.

Shawn J. Goff
źródło
6
Gdy widzisz „X lub Y”, testujesz X. Jeśli to prawda, znasz już odpowiedź na „X lub Y” (to prawda), więc nie musisz testować Y. Jeśli to prawda, nie znasz odpowiedz na „X lub Y”, więc musisz przetestować Y. Gdy zobaczysz „X i Y”, przetestujesz X. Jeśli jest to fałsz, znasz już odpowiedź na „X i Y” (to jest fałsz), więc nie ma potrzeby testowania Y. Jeśli X jest prawdą, musisz przetestować Y, aby sprawdzić, czy „X i Y” są prawdziwe.
David Schwartz
2
Zamiast „jeśli lewa strona zwraca zero”, napisałbym „jeśli status wyjścia polecenia po lewej stronie wynosi zero”. Uważam, że „powrót” jest nieco niejednoznaczny, ponieważ dane wyjściowe i status wyjścia można uznać za „wartości zwrotne”
glenn jackman,
Nie tylko możesz „ uważać [ ... ] się za program”, ale w wielu przypadkach tak jest . Zazwyczaj jest w pliku /bin/[lub /usr/bin/[.
LS
5
Programiści C uznają to za bardzo mylące. Tam 0 oznacza fałsz ... Podczas gdy w shellscripting 0 oznacza prawda ... Umysł zawalony.
Calmarius
Innym, o którym możesz wspomnieć, jest testzamiast iflub [. A if [i if testwydają się być przeplatane [i testbez widocznego ładu i składu. testpojawia się czasami, np. na config.site dla bibliotek dostawców na Fedorze x86_64 .
58

Oto mój ściągawka:

  • „A; B” Uruchom A, a następnie B, niezależnie od powodzenia A
  • „A && B” Uruchom B, jeśli A się powiedzie
  • „A || B” Uruchom B, jeśli A nie powiedzie się
  • „A” Uruchom A w tle.
użytkownik177073
źródło
Działa tutaj kilka interesujących paraleli rachunku lambda, pokazanych w działającym JavaScript (zdefiniuj zmienne w kolejności); "left (aka true)": (a => b => a). "prawo (aka false)": (a => b => b). „A; B” „następnie” (a => b => (() => b())(a())). „A && B” „jeśli bez innego (kiedy)” (a => b => a()(() => right)(b)). „A || B” „inaczej bez if (chyba)” (a => b => a()(b)(() => right)). „a&&b || c” „ifThenElse” (a => b => c => (unless(when(a)(b))(c))()).
Dmitry
1
zwróć uwagę, że w bash lewy jest analogiczny 0 / pusty ciąg, prawy analogiczny jest wszystko inne.
Dmitry
27

rozwinięcie odpowiedzi @ Shawn-j-Goff z góry, &&jest logicznym AND i ||logicznym OR.

Zobacz część Advanced Bash Scripting Guide. Niektóre treści z linku dla odniesienia użytkownika, jak poniżej.

&& I

if [ $condition1 ] && [ $condition2 ]
#  Same as:  if [ $condition1 -a $condition2 ]
#  Returns true if both condition1 and condition2 hold true...

if [[ $condition1 && $condition2 ]]    # Also works.
#  Note that && operator not permitted inside brackets
#+ of [ ... ] construct.

|| LUB

if [ $condition1 ] || [ $condition2 ]
# Same as:  if [ $condition1 -o $condition2 ]
# Returns true if either condition1 or condition2 holds true...

if [[ $condition1 || $condition2 ]]    # Also works.
#  Note that || operator not permitted inside brackets
#+ of a [ ... ] construct.
Tim Kennedy
źródło
10

Z mojego doświadczenia korzystam z && i || aby zredukować instrukcję if do jednego wiersza.

Załóżmy, że szukamy pliku o nazwie /root/Sample.txt, wówczas tradycyjna iteracja wyglądałaby następująco w powłoce:

if [ -f /root/Sample.txt ]
then
    echo "file found"
else
    echo "file not found"
fi

Te 6 linii można zredukować do jednej linii:

[[ -f /root/Sample.txt ]] && echo "file found" || echo "file not found"

Podczas uruchamiania kilku iteracji w celu ustawiania zmiennych lub tworzenia plików itp. Życie jest łatwiejsze, a skrypt wygląda na bardziej płynny przy użyciu pojedynczej linii, jeśli funkcja, jego jedyną wadą jest to, że trudniej jest zaimplementować wiele poleceń z jednej iteracji możesz skorzystać z funkcji.

syme89
źródło
To jest fajne. Przypomina mi kod objc (a == b)? Val = 1: val = 2;
GeneCode
Jak mogę użyć tego polecenia, jeśli chcę uruchomić proces w tle za pomocą „&”? Dostaję błąd składniowy dla./someScript.sh & && echo 'ok' || echo 'ko'
Katie
3

Istnieje pojęcie „skrótu”.

Kiedy (expr1 && expr2)jest oceniane - expr2jest oceniane tylko wtedy, gdy zostanie exp1ocenione na „prawda”. Jest tak, ponieważ oba expr1ORAZ expr2muszą być prawdziwe, (expr1 && expr2)aby były prawdziwe. Jeśli expr1wartość „false” expr2NIE jest oceniana (skrót), ponieważ (expr1 && expr2)jest już „flase”.

Spróbuj wykonać następujące czynności - zakładając, że plik F1istnieje i plik F2nie istnieje:

( [ -s F1 ] && echo "File Exists" )  # will print "File Exists" - no short cut
( [ -s F2 ] && echo "File Exists" )  # will NOT print "File Exists" - short cut

Podobnie jest w przypadku ||(lub) - ale skróty są odwrócone.

Larry
źródło
4
Logika jest zwykle nazywana „zwarciem”. Nigdy nie widziałem użycia słowa „skrót”. Wspominam o tym, aby pomóc w znalezieniu referencji.
LS
-1

Przykłady w odpowiedzi Shawna J. Goffa są poprawne, ale wyjaśnienie jest odwrotne. Proszę sprawdzić:

Prawa strona && zostanie oceniona tylko wtedy, gdy stan wyjścia z lewej strony to NONZERO. || jest odwrotnie: ocenia prawą stronę tylko wtedy, gdy status wyjścia z lewej strony to ZERO.

Try2Help
źródło
3
Zdajesz sobie sprawę, że w przypadku powłok zerowy kod wyjścia ma wartość true, a zatem niezerowy kod wyjścia po lewej stronie &&powoduje, że całe wyrażenie zwraca false ?
kontr-
1
Ktoś nie zatwierdził Twoich zmian, ponieważ nie była to Twoja odpowiedź. Jeśli uważasz, że jakaś odpowiedź jest niepoprawna, oceń ją i ewentualnie zostaw komentarz; jeśli uważasz, że wymaga to zmiany, zostaw komentarz. Edycja służy do korygowania gramatyki, formatowania i błędów ortograficznych, które nie zmieniają znaczenia odpowiedzi.
techraf
1
@countermode Przepraszam, masz rację, myślałem w Linuksie zero = false i niezerowy = true (jak w C i wielu innych językach / środowiskach / platformach). Przepraszam za nieporozumienie.
Try2Help,