Uso confuso de && y || operadores


93

Estaba hojeando un /etc/rc.d/init.d/sendmailarchivo (sé que esto casi nunca se usa, pero estoy estudiando para un examen), y estoy un poco confundido sobre &&los ||operadores y los operadores. He leído dónde se pueden usar en declaraciones como:

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

Sin embargo, este script muestra declaraciones de una sola línea como:

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

Estos parecen estar utilizando los operadores &&y ||para obtener respuestas basadas en pruebas, pero no he podido desenterrar documentación sobre este uso particular de estos operadores. ¿Alguien puede explicar lo que hacen en este contexto particular?

Respuestas:


141

El lado derecho de &&solo se evaluará si el estado de salida del lado izquierdo es cero (es decir, verdadero). ||es lo opuesto: evaluará el lado derecho solo si el estado de salida del lado izquierdo no es cero (es decir, falso).

Puede considerar [ ... ]ser un programa con un valor de retorno. Si la prueba interna se evalúa como verdadera, devuelve cero; de lo contrario, devuelve un valor distinto de cero.

Ejemplos:

$ false && echo howdy!

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

$ false || echo howdy!
howdy!

Notas adicionales:

Si lo hace which [, es posible que vea que [realmente apunta a un programa. Sin embargo, generalmente no es el que se ejecuta en los scripts; corre type [para ver lo que realmente se corre. Si usted wan para tratar de usar el programa, acaba de dar la ruta completa de esta manera: /bin/[ 1 = 1.


66
Cuando ve "X o Y", prueba X. Si es cierto, ya sabe la respuesta a "X o Y" (es cierto), por lo que no es necesario probar Y. Si es cierto, no sabe responda a "X o Y", por lo que debe probar Y. Cuando vea "X e Y", pruebe X. Si es falso, ya sabe la respuesta a "X e Y" (es falso), entonces no es necesario probar Y. Si X es verdadero, entonces necesita probar Y para ver si "X e Y" es verdadero.
David Schwartz el

2
En lugar de "si el lado izquierdo devuelve cero", escribiría "si el estado de salida del comando del lado izquierdo es cero". Encuentro "retorno" un poco ambiguo ya que la salida y el estado de salida pueden considerarse ambos como "valores de retorno"
Glenn Jackman

No solo puede " considerar [ ... ] que es un programa", en muchos casos lo es . Es comúnmente en el archivo /bin/[o /usr/bin/[.
LS

55
Los programadores de C encontrarán esto súper confuso. Hay 0 significa falso ... Mientras que en shellscripting 0 significa verdadero ... Mente alucinada.
Calmarius

Otro que podrías mencionar es en testlugar de ifo [. Y if [y if testparecen estar intercalados con [y testsin rima ni razón aparente. testaparece ocasionalmente, como en config.site para bibliotecas de proveedores en Fedora x86_64 .

59

Aquí está mi hoja de trucos:

  • "A; B" Ejecuta A y luego B, independientemente del éxito de A
  • "A && B" Ejecuta B si A tuvo éxito
  • "A || B" Ejecuta B si A falla
  • "A &" Ejecutar A en segundo plano.

Hay algunos paralelos interesantes de cálculo lambda que se están demostrando aquí en JavaScript de trabajo (defina las variables en orden); "izquierda (también conocido como verdadera)": (a => b => a). "derecho (también conocido como falso)": (a => b => b). "A; B" "entonces" (a => b => (() => b())(a())). "A y B" "si no hay otra cosa (cuando)" (a => b => a()(() => right)(b)). "A || B" "más sin if (a menos que)" (a => b => a()(b)(() => right)). "a && b || c" "ifThenElse" (a => b => c => (unless(when(a)(b))(c))()).
Dmitry

1
tenga en cuenta que en bash, la izquierda es análoga 0 / cadena vacía, la derecha análoga es todo lo demás.
Dmitry

28

expandir la respuesta de @ Shawn-j-Goff desde arriba, &&es un AND lógico y ||es un OR lógico.

Consulte esta parte de la Guía avanzada de secuencias de comandos Bash. Algunos de los contenidos del enlace para referencia del usuario como a continuación.

&& AND

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.

11

Desde mi experiencia, uso el && y || para reducir una declaración if a una sola línea.

Digamos que estamos buscando un archivo llamado /root/Sample.txt, entonces la iteración tradicional sería la siguiente en el shell:

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

Estas 6 líneas se pueden reducir a una sola línea:

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

Cuando se ejecutan algunas iteraciones para establecer variables o crear archivos, etc., la vida es más fácil y la secuencia de comandos se ve más elegante usando la línea única si funciona, su único inconveniente es que se vuelve un poco más difícil implementar múltiples comandos desde una sola iteración. Puedes hacer uso de las funciones.


Esto es genial Me recuerda al código objc (a == b)? Val = 1: val = 2;
GeneCode

¿Cómo puedo usar este comando cuando quiero ejecutar un proceso en segundo plano con "&"? Me sale un error de sintaxis para./someScript.sh & && echo 'ok' || echo 'ko'
Katie

4

Hay una noción de "atajo".

Cuando (expr1 && expr2)se evalúa: expr2solo se evalúa si se exp1evalúa como "verdadero". Esto es porque ambos expr1Y expr2tienen que ser verdad para (expr1 && expr2)ser verdad. Si se expr1evalúa como "falso" expr2NO se evalúa (atajo) porque (expr1 && expr2)ya está "plano"

Pruebe lo siguiente: suponga que el archivo F1existe y que el archivo F2no existe:

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

De manera similar para ||(o), pero se invierte el atajo.


55
La lógica generalmente se conoce como "cortocircuito". Nunca he visto la frase "atajo" utilizada. Menciono esto para ayudar a encontrar referencias.
LS

-1

Los ejemplos en la respuesta de Shawn J. Goff son correctos, pero la explicación es al revés. Por favor, compruebe:

El lado derecho de && solo se evaluará si el estado de salida del lado izquierdo es NO CERO. || es lo contrario: evaluará el lado derecho solo si el estado de salida del lado izquierdo es CERO.


3
¿Sabe que para los shells el código de salida cero se evalúa como verdadero y, por lo tanto, el código de salida distinto de cero en el lado izquierdo de los &&resultados en toda la expresión devuelve falso ?
contramode

1
Alguien no aprobó sus ediciones porque no fue su respuesta. Si cree que alguna respuesta es incorrecta, debe rechazarla y posiblemente dejar un comentario; Si cree que requiere un cambio, debe dejar un comentario. La edición es para corregir errores de gramática, formato y ortografía que no cambian el significado de la respuesta.
techraf

1
@countermode Lo siento, tienes razón, pensé en Linux zero = false y non-zero = true (como en C y muchos otros lenguajes / entornos / plataformas). Me disculpo por el malentendido.
Try2Help
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.