Estoy aprendiendo sobre las estructuras de toma de decisiones y me encontré con estos códigos:
if [ -f ./myfile ]
then
cat ./myfile
else
cat /home/user/myfile
fi
[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile
Ambos se comportan igual. ¿Hay alguna ventaja en usar una forma de la otra?
shell-script
syntax
control-flow
Subhaa Chandar
fuente
fuente
Respuestas:
No, construcciones
if A; then B; else C; fi
y noA && B || C
son equivalentes .Con
if A; then B; else C; fi
, el comandoA
siempre se evalúa y ejecuta (al menos se intenta ejecutarlo) y luego se evalúa y ejecuta el comandoB
o el comandoC
.Con
A && B || C
, que es la misma para los comandosA
yB
pero diferente paraC
: comandoC
se evalúa y ejecuta si bienA
falla oB
falla.En su ejemplo, suponga que
chmod u-r ./myfile
, entonces, a pesar de tener[ -f ./myfile ]
éxito, lo harácat /home/user/myfile
Mi consejo: use
A && B
oA || B
todo lo que quiera, esto sigue siendo fácil de leer y comprender y no hay trampa. Pero si te refieres a si ... entonces ... más ... entonces úsaloif A; then B; else C; fi
.fuente
A la mayoría de las personas les resulta más fácil comprender la
if
...then
...else
...fi
forma.Para el
a && b || c
, debe asegurarse de queb
devuelve verdadero. Esta es una causa de errores sutiles y es una buena razón para evitar este estilo. Si b no devuelve verdadero, estos no son lo mismo.Para pruebas y acciones muy cortas que no tienen una cláusula else, la longitud acortada es atractiva, p. Ej.
&&
y||
sonshort circuiting operators
, tan pronto como se conozca el resultado de otras pruebas que no sean necesarios se pasan por alto.a && b || c
se agrupa como(a && b) || c
. Primeroa
se corre. Si sefails
define como que no devuelve un estado de salida de 0, entonces el grupo(a && b)
es conocidofail
yb
no necesita ejecutarse. El||
no sabe el resultado de la expresión, por lo que debe ejecutarsec
. Sia
tiene éxito (devuelve cero), el&&
operador aún no sabe el resultado dea && b
lo que tiene que correrb
para averiguarlo. Sib
tiene éxito, entoncesa && b
tiene éxito y||
sabe que el resultado general es exitoso, por lo que no necesita ejecutarsec
. Sib
falla entonces||
aún no conoce el valor de la expresión, por lo que debe ejecutarsec
.fuente
El operador && ejecuta el siguiente comando si el comando anterior tuvo una ejecución exitosa (código de salida devuelto ($?) 0 = lógico verdadero).
En el formulario
A && B || C
, se evalúa el comando (o condición) A y si A devuelve verdadero (éxito, código de salida 0), se ejecuta el comando B. Si A falla (por lo tanto devolverá falso - el código de salida es diferente a 0) y / o B falla (devolver falso ), entonces se ejecutará el comando C.También el
&&
operador se utiliza como AND en las comprobaciones de condición y el operador||
funciona como OR en las comprobaciones de condición.Dependiendo de lo que desee hacer con su script, el formulario
A && B || C
puede usarse para verificaciones de condición como su ejemplo o puede usarse para encadenar comandos y garantizar una serie de comandos que se ejecutarán si los comandos anteriores tuvieron un código de salida 0 exitoso .Por esta razón, es común ver comandos como:
do_something && do_something_else_that_depended_on_something
.Ejemplos:
apt-get update && apt-get upgrade
si la actualización falla, la actualización no se ejecuta (tiene sentido en el mundo real ...).mkdir test && echo "Something" > test/file
La parte
echo "Something"
se ejecutará solo simkdir test
fue exitosa y la operación devolvió el código de salida 0 ../configure --prefix=/usr && make && sudo make install
Generalmente se encuentra en la compilación de trabajos para encadenar los comandos dependientes necesarios.
Si intenta implementar "cadenas" anteriores con if , entonces , de lo contrario , necesitará muchos más comandos y comprobaciones (y, por lo tanto, más código para escribir, más cosas que saldrán mal) para una tarea simple.
Además, tenga en cuenta que los comandos encadenados con && y || son leídos por shell de izquierda a derecha. Es posible que deba agrupar comandos y verificaciones de condición con corchetes para depender del siguiente paso en la salida exitosa de algunos comandos anteriores. Por ejemplo, mira esto:
O un ejemplo de la vida real:
Tenga en cuenta que algunos comandos devuelven diferentes códigos de salida según el proceso ejecutado, o devuelven diferentes códigos según sus acciones (por ejemplo, el comando GNU
diff
, devuelve 1 si dos archivos difieren y 0 si no lo hacen). Dichos comandos deben tratarse con cuidado en && y || .También solo para tener todo el rompecabezas juntos, tenga en cuenta la concatenación de comandos utilizando el
;
operador. Con un formato,A;B;C
todos los comandos se ejecutarán en serie sin importar cuál fue el código de comando de salidaA
yB
.fuente
Gran parte de la confusión sobre esto puede deberse a la documentación de bash que llama a estas listas AND y OR . Si bien son lógicamente similares al
&&
y se||
encuentran dentro de los corchetes, funcionan de manera diferente.Algunos ejemplos pueden ilustrar esto mejor ...
Si
cmda
sale verdadero,cmdb
se ejecuta.Si
cmda
sale falso,cmdb
NO se ejecuta, perocmdc
es.Cómo
cmda
se ignora las salidas.Si
cmdb
sale verdadero,cmdc
se ejecuta.Si
cmdb
sale falso,cmdc
NO se ejecuta ycmdd
es.Si
cmda
sale verdadero,cmdb
se ejecuta, seguido decmdc
.Si
cmda
sale falso,cmdb
NO se ejecuta perocmdc
es.¿Eh? ¿Por qué se
cmdc
ejecuta?Porque para el intérprete, un punto y coma (
;
) y una nueva línea significan exactamente lo mismo. Bash ve esa línea de código como ...Para lograr lo que se espera, debemos encerrar
cmdb; cmdc
dentro de llaves para convertirlas en un Compound Command (comando de grupo) . El punto y coma de terminación adicional es solo un requisito de la{ ...; }
sintaxis. Entonces tenemos ...cmda && { cmdb; cmdc; }
Si
cmda
sale verdadero,cmdb
se ejecuta, seguido decmdc
.Si
cmda
sale falso, ningunocmdb
ocmdc
se ejecuta.La ejecución continúa con la siguiente línea.
Uso
Las listas de comandos condicionales son más útiles para regresar tan pronto como sea posible de las funciones y así evitar interpretar y ejecutar un montón de código innecesario. Sin embargo, los retornos de funciones múltiples significan que uno debe ser obsesivo acerca de mantener las funciones cortas para que sea más fácil asegurarse de que todas las condiciones posibles estén cubiertas.
Aquí hay un ejemplo de un código en ejecución ...
fuente