¿Por qué es el patrón "comando || verdadero "útil?

79

Actualmente estoy explorando los paquetes de Debian, y he estado leyendo algunos ejemplos de código. Y en cada línea, por ejemplo, el postinstguión es un patrón.

some command || true
another command || true

Entonces, si algún comando falla, la línea devuelve verdadero, pero no veo cómo esto afecta la salida del programa.

carpintero
fuente
55
Para su información, ||:es otra forma idiomática de escribir esto ( :es otra entrada en la tabla integrada que apunta a true, pero se garantiza que será una creación incluso de vuelta a Bourne; dicho eso, para POSIX sh, truetambién se garantiza que es una característica incorporada, por lo que es más brevedad que eficiencia en tiempos aún remotamente modernos).
Charles Duffy

Respuestas:

151

La razón de este patrón es que los scripts de mantenedor en los paquetes Debian tienden a comenzar set -e, lo que hace que el shell se cierre tan pronto como cualquier comando (estrictamente hablando, pipeline, list o comando compuesto) salga con un estado distinto de cero. Esto asegura que los errores no se acumulen: tan pronto como algo sale mal, el script aborta.

En los casos en que un comando en el script puede fallar, la adición || trueasegura que el comando compuesto resultante siempre salga con el estado cero, por lo que el script no se cancela. Por ejemplo, eliminar un directorio no debería ser un error grave (evitar que se elimine un paquete); entonces usaríamos

rmdir ... || true

ya rmdirque no tiene una opción para decirle que ignore los errores.

Stephen Kitt
fuente
44
Bueno, sin set -eninguna necesidad || true, pensé que era importante proporcionar el contexto. Si observa cosas extrañas en POWER, ¡le recomiendo que presente errores ( reportbug)!
Stephen Kitt
16
@MichaelFelt, en realidad set -eno es solo una "convención de Debian", sino un buen patrón de programación que siempre se debe usar. Ver. por ejemplo davidpashley.com/articles/writing-robust-shell-scripts~~V~~singular~~3rd
kay
2
según la pregunta aquí: ¿por qué usar || trueset -e es el contexto probable y probablemente el más común? Me inclino ante esta respuesta! Literalmente, sin embargo, es útil siempre que el estado de salida se considere irrelevante Y (como agrega el enlace del artículo) No estoy usando el estado de salida como parte de mi control de script. Veo la utilidad (in set -e) pero no iría tan lejos como lo hace el artículo y diría "Cada script que escriba debe incluir set -e en la parte superior". Es un estilo de programación. "SIEMPRE | Cada" incluye su propio conjunto de trampas, también conocido como absoluto: las soluciones con comodines ALWAYSeventualmente fracasarán eventualmente, sin viajes gratuitos.
Michael Felt
1
@Kay Esa es una perspectiva popular en la actualidad, pero en última instancia está llena de numerosas suposiciones que limitan la portabilidad del script. Hay inconsistencias históricas con el set -ecomportamiento. Es posible que no le importe si sus únicos objetivos son bashy los otros proyectiles relativamente recientes en los que vive /bin/sh, pero la situación es más matizada cuando desea soportar los antiguos proyectiles / sistemas.
mtraceur
2
@StephenKitt Claro que sí. Hay una páginaset -e muy completa que documenta los comportamientos de diferentes proyectiles de Sven Mascheck , aunque esta página también documenta una gran cantidad de proyectiles históricos / antiguos irrelevantes en la actualidad. También hay estas dos páginas con un enfoque moderno más estrecho (busque "set -e"): página "lintsh" , documentación de shell portátil de autoconf -> Limitación de subpágina
Builtins
32

Si bien no afecta la salida del programa que acaba de ejecutarse, permite que la persona que llama proceda como si todo estuviera bien, también afecta la lógica futura.

Reformulado: enmascara el estado de error del comando anterior.

michael@x071:[/usr/sbin]cat /tmp/false.sh
#!/bin/sh
false

michael@x071:[/usr/sbin]cat /tmp/true.sh 
#!/bin/sh
false || true

michael@x071:[/usr/sbin]sh /tmp/false.sh; echo $?
1
michael@x071:[/usr/sbin]sh /tmp/true.sh; echo $? 
0
Michael sintió
fuente
66
Eso es cierto, pero no responde por qué es útil enmascarar el estado de salida de un comando.
moopet
44
set -e significa que el script terminará instantáneamente con un retorno distinto de cero. ¡Es posible que, en ese lugar localizado, no quieras que eso suceda!
rackandboneman
Soy una persona simple, y para mí la única razón para enmascarar el estado del error es porque está "en el camino". set -e comete cualquier error "en el camino" si antes no le importaba. Me gusta la discusión porque la veo como una buena manera de ayudarme a depurar mis scripts y escribir lógica adicional para responder a un error (por ejemplo, || print - "xxx existía aquí distinto de cero". Es más probable que tenga un función de shell 'fatal' y tengo "algo || fatal" infeliz para mí ". En mi opinión, un script debe informar un estado fallido, o no me importa. -e plus || verdadero es enmascarar errores. Si eso es lo que quiero - bien, si no, me faltan errores
Michael Felt
lo que tengo que preguntarme es: es || verdadero: una muleta de codificación (forma perezosa de sortear / pasar un error con el que no quiero tratar ahora; una herramienta de depuración (-e pero no || verdadero) o simplemente el dogma de alguien sobre lo que es una buena práctica de codificación. En otras palabras - Lo veo como una característica, con un beneficio potencial. No lo veo como una varita mágica para curar todo. En resumen, así como la belleza está en el ojo del espectador, set -ey la || trueutilidad estará definida por los rasgos y objetivos de el programador.
Michael fieltro
66
@MichaelFelt Considere: git remote remove foo || true git remote add foo http://blah- queremos ignorar el error si el control remoto no existe.
user253751