Los operadores &&
y no||
son reemplazos en línea exactos para if-then-else. Aunque si se usan con cuidado, pueden lograr lo mismo.
Una sola prueba es sencilla e inequívoca ...
[[ A == A ]] && echo TRUE # TRUE
[[ A == B ]] && echo TRUE #
[[ A == A ]] || echo FALSE #
[[ A == B ]] || echo FALSE # FALSE
Sin embargo, intentar agregar múltiples pruebas puede producir resultados inesperados ...
[[ A == A ]] && echo TRUE || echo FALSE # TRUE (as expected)
[[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
[[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
[[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)
¿Por qué se hacen eco FALSO y VERDADERO?
Lo que sucede aquí es que no nos hemos dado cuenta de eso &&
y ||
somos operadores sobrecargados que actúan de manera diferente dentro de los corchetes de prueba condicionales [[ ]]
que en la lista AND y OR (ejecución condicional) que tenemos aquí.
Desde la página de manual de bash (editado) ...
Liza
Una lista es una secuencia de una o más tuberías separadas por uno de los operadores;, &, &&, o ││, y opcionalmente terminadas por uno de;, &, o. De estos operadores de lista, && y ││ tienen la misma precedencia, seguidos de; y &, que tienen igual precedencia.
Puede aparecer una secuencia de una o más líneas nuevas en una lista en lugar de un punto y coma para delimitar los comandos.
Si el operador de control termina un comando &, el shell ejecuta el comando en segundo plano en un subshell. El shell no espera a que termine el comando y el estado de retorno es 0. Comandos separados por a; se ejecutan secuencialmente; el shell espera que cada comando termine a su vez. El estado de retorno es el estado de salida del último comando ejecutado.
Las listas AND y OR son secuencias de uno o más canales separados por los operadores de control && y ││, respectivamente. Las listas AND y OR se ejecutan con asociatividad izquierda.
Una lista AND tiene la forma ...
command1 && command2
Command2 se ejecuta si, y solo si, command1 devuelve un estado de salida de cero.
Una lista OR tiene la forma ...
command1 ││ command2
Command2 se ejecuta si y solo si command1 devuelve un estado de salida distinto de cero.
El estado de retorno de las listas AND y OR es el estado de salida del último comando ejecutado en la lista.
Volviendo a nuestro último ejemplo ...
[[ A == B ]] || echo FALSE && echo TRUE
[[ A == B ]] is false
|| Does NOT mean OR! It means...
'execute next command if last command return code(rc) was false'
echo FALSE The 'echo' command rc is always true
(i.e. it successfully echoed the word "FALSE")
&& Execute next command if last command rc was true
echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"
Bueno. Si eso es correcto, ¿por qué el penúltimo ejemplo hace eco de algo?
[[ A == A ]] || echo FALSE && echo TRUE
[[ A == A ]] is true
|| execute next command if last command rc was false.
echo FALSE Since last rc was true, shouldn't it have stopped before this?
Nope. Instead, it skips the 'echo FALSE', does not even try to
execute it, and continues looking for a `&&` clause.
&& ... which it finds here
echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"
El riesgo de errores lógicos cuando se usa más de uno &&
o ||
en una lista de comandos es bastante alto.
Recomendaciones
Un solo &&
o ||
en una lista de comandos funciona como se esperaba, por lo que es bastante seguro. Si es una situación en la que no necesita una cláusula else, puede ser más claro seguir algo como lo siguiente (las llaves se requieren para agrupar los últimos 2 comandos) ...
[[ $1 == --help ]] && { echo "$HELP"; exit; }
Los operadores múltiples &&
y ||
, donde cada comando, excepto el último, es una prueba (es decir, entre corchetes [[ ]]
), también suelen ser seguros, ya que todos menos el último operador se comportan como se esperaba. El último operador actúa más como una then
o else
cláusula.
&&
y||
shell como encmd1 && cmd2 || cmd3
tienen la misma precedencia, los&&
in((...))
y[[...]]
tienen precedencia sobre||
(((a || b && c))
is((a || (b && c)))
). Lo mismo va para-a
/-o
entest
/[
yfind
e&
/|
enexpr
.