Uso confuso di && e || operatori


94

Stavo sfogliando un /etc/rc.d/init.d/sendmailfile (so che questo non viene quasi mai usato, ma sto studiando per un esame), e sono diventato un po 'confuso riguardo agli &&e agli ||operatori. Ho letto dove possono essere utilizzati in dichiarazioni come:

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

Tuttavia, questo script mostra istruzioni a riga singola come:

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

Questi sembrano utilizzare gli operatori &&e ||per ottenere risposte basate su test, ma non sono stato in grado di scavare nella documentazione relativa a questo particolare utilizzo di questi operatori. Qualcuno può spiegare cosa fanno questi in questo particolare contesto?

Risposte:


141

Il lato destro di &&verrà valutato solo se lo stato di uscita del lato sinistro è zero (cioè vero). ||è l'opposto: valuterà il lato destro solo se lo stato di uscita del lato sinistro è diverso da zero (cioè falso).

Puoi considerare [ ... ]di essere un programma con un valore di ritorno. Se il test interno restituisce true, restituisce zero; restituisce altrimenti diverso da zero.

Esempi:

$ false && echo howdy!

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

$ false || echo howdy!
howdy!

Note extra:

Se lo fai which [, potresti vedere che in [realtà punta a un programma! Di solito non è in realtà quello che viene eseguito negli script; corri type [per vedere cosa viene effettivamente eseguito. Se si wan per provare a utilizzare il programma, basta dare il percorso completo in questo modo: /bin/[ 1 = 1.


6
Quando vedi "X o Y", esegui il test di X. Se è vero, conosci già la risposta a "X o Y" (è vero), quindi non è necessario testare Y. Se è vero, non conosci il rispondi a "X o Y", quindi devi testare Y. Quando vedi "X e Y", controlli X. Se è falso, conosci già la risposta a "X e Y" (è falso), quindi non c'è bisogno di testare Y. Se X è vero, allora devi testare Y per vedere se "X e Y" è vero.
David Schwartz,

2
Invece di "se il lato sinistro restituisce zero", scriverei "se lo stato di uscita del comando sul lato sinistro è zero". Trovo che "return" sia un po 'ambiguo in quanto l'uscita e lo stato di uscita possono essere entrambi considerati "valori di ritorno"
glenn jackman,

Non solo puoi " considerare [ ... ] di essere un programma", in molti casi lo è . È comunemente nel file /bin/[o /usr/bin/[.
LS,

5
I programmatori C lo troveranno super confuso. C'è 0 significa falso ... Mentre in shellscripting 0 significa vero ... Mente esplosa.
Calmarius,

Un altro che potresti menzionare è testinvece di ifo [. E if [e if testsembrano essere intervallati [e testsenza apparente rima o ragione. testappare occasionalmente, come su config.site per le librerie dei distributori su Fedora x86_64 .

60

Ecco il mio cheat sheet:

  • "A; B" Esegui A e poi B, indipendentemente dal successo di A
  • "A && B" Esegui B se A ha avuto successo
  • "A || B" Esegui B se A fallisce
  • "A &" Esegui A in background.

Ci sono alcuni parallelismi di calcolo lambda in corso qui dimostrati nel funzionamento di JavaScript (definire le variabili in ordine); "a sinistra (aka vero)": (a => b => a). "destra (aka false)": (a => b => b). "A; B" "poi" (a => b => (() => b())(a())). "A && B" "se senza altro (quando)" (a => b => a()(() => right)(b)). "A || B" "altrimenti senza if (salvo)" (a => b => a()(b)(() => right)). "a && b || c" "ifThenElse" (a => b => c => (unless(when(a)(b))(c))()).
Dmitry,

1
nota che in bash, left è analogo 0 / stringa vuota, right analogo è tutto il resto.
Dmitry,

28

espandersi sulla risposta di @ Shawn-j-Goff dall'alto, &&è un AND logico ed ||è un OR logico.

Vedi questa parte della Guida agli script avanzati di Bash. Alcuni dei contenuti del link per riferimento utente come di seguito.

&& E

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.

|| O

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.

12

Dalla mia esperienza utilizzo && e || per ridurre un'istruzione if su una singola riga.

Supponiamo che stiamo cercando un file chiamato /root/Sample.txt, quindi l'iterazione tradizionale sarebbe la seguente nella shell:

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

Queste 6 linee possono essere ridotte a una sola riga:

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

Quando si eseguono alcune iterazioni per impostare variabili o per creare file, ecc., La vita è più semplice e lo script sembra sfarfallio utilizzando la singola riga se la funzione, il solo svantaggio è che diventa un po 'più difficile implementare più comandi da una singola iterazione tuttavia puoi usare le funzioni.


Questo è fico. Mi ricorda il codice objc (a == b)? Val = 1: val = 2;
GeneCode

Come posso usare questo comando quando voglio eseguire un processo in background con "&"? Ottengo un errore di sintassi per./someScript.sh & && echo 'ok' || echo 'ko'
Katie,

4

C'è una nozione di "taglio corto".

Quando (expr1 && expr2)viene valutato: expr2viene valutato solo se viene exp1valutato come "vero". Questo perché sia expr1AND che expr2deve essere vero per (expr1 && expr2)essere vero. Se viene expr1valutato "falso" expr2NON viene valutato (scelta rapida) perché (expr1 && expr2)è già "flase".

Prova quanto segue: supponi che il file F1esista e il file F2non esista:

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

Allo stesso modo per ||(o) - ma il taglio corto è invertito.


5
La logica viene generalmente definita "corto circuito". Non ho mai visto la frase "taglio corto" usata. Cito questo per aiutare a trovare riferimenti.
LS,

-1

Gli esempi nella risposta di Shawn J. Goff sono corretti, ma la spiegazione è viceversa. Si prega di controllare:

Il lato destro di && verrà valutato solo se lo stato di uscita del lato sinistro è NONZERO. || è l'opposto: valuterà il lato destro solo se lo stato di uscita del lato sinistro è ZERO.


3
Sai che per le shell il codice di uscita zero restituisce true e quindi un codice di uscita diverso da zero sul lato sinistro dei &&risultati nell'intera espressione per restituire false ?
contromodale,

1
Qualcuno non ha approvato le tue modifiche perché non era la tua risposta. Se ritieni che una risposta non sia corretta, dovresti ridimensionarla ed eventualmente lasciare un commento; se ritieni che richieda una modifica, dovresti lasciare un commento. La modifica serve a correggere errori grammaticali, di formattazione e di ortografia che non cambiano il significato della risposta.
techraf,

1
@countermode Mi dispiace, hai ragione, ho pensato in Linux zero = false e nonzero = true (come in C e molti altri linguaggi / ambienti / piattaforme). Chiedo scusa per l'incomprensione.
Try2Help
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.