Me he encontrado con algunas secuencias de comandos como esta recientemente:
( set -e ; do-stuff; do-more-stuff; ) || echo failed
Esto me parece bien, ¡pero no funciona! El set -eno se aplica, cuando se agrega el ||. Sin eso, funciona bien:
$ ( set -e; false; echo passed; ); echo $?
1
Sin embargo, si agrego el ||, set -ese ignora el:
$ ( set -e; false; echo passed; ) || echo failed
passed
El uso de un shell real separado funciona como se esperaba:
$ sh -c 'set -e; false; echo passed;' || echo failed
failed
He intentado esto en varios shells diferentes (bash, dash, ksh93) y todos se comportan de la misma manera, por lo que no es un error. ¿Alguien puede explicar esto?
                    
                        shell
                                shell-script
                                
                    
                    
                        Científico loco
fuente
                
                fuente

||exterior de la subshell afecta el comportamiento dentro de la subshell.(set -e; echo 1; false; echo 2)con(set -e; echo 1; false; echo 2) || echo 3Respuestas:
De acuerdo con este hilo , es el comportamiento que POSIX especifica para usar "
set -e" en una subshell.(También me sorprendió).
Primero, el comportamiento:
Las notas del segundo post,
Hay un poco más en el cuarto post, también de Eric Blake,
Este comportamiento es definitivamente sorprendente. Es contrario a la intuición: uno esperaría que la reactivación
set -etuviera un efecto, y que el contexto circundante no tendría precedentes; Además, la redacción del estándar POSIX no deja esto particularmente claro. Si lo lee en el contexto donde el comando falla, la regla no se aplica: solo se aplica en el contexto circundante, sin embargo, se aplica por completo.fuente
set -e; (false; echo passed;) || echo failed. No me sorprende, en realidad, que -e se ignore en este caso dada la redacción de la norma. Sin embargo, en mi caso, configuro explícitamente -e en la subshell y espero que la subshell salga en caso de falla. No hay una lista AND-OR en el subshell ...ify||y&&son infecciosas? esto es absurdoDe hecho,
set -eno tiene ningún efecto dentro de las subcapas si usa el||operador después de ellas; por ejemplo, esto no funcionaría:Aaron D. Marasco en su respuesta hace un gran trabajo al explicar por qué se comporta de esta manera.
Aquí hay un pequeño truco que puede usarse para solucionar esto: ejecute el comando interno en segundo plano y luego espere inmediatamente. El
waitincorporado devolverá el código de salida del comando interno, y ahora está usando||despuéswait, no la función interna, por lo queset -efunciona correctamente dentro de este último:Aquí está la función genérica que se basa en esta idea. Debería funcionar en todos los shells compatibles con POSIX si elimina las
localpalabras clave, es decir, reemplace todolocal x=ycon solox=y:Ejemplo de uso:
Ejecutando el ejemplo:
Lo único que debe tener en cuenta al usar este método es que todas las modificaciones de las variables de Shell realizadas desde el comando al que pasa
runno se propagarán a la función de llamada, porque el comando se ejecuta en una subshell.fuente
No descartaría que sea un error solo porque varios proyectiles se comportan de esa manera. ;-)
Tengo más diversión para ofrecer:
¿Puedo citar a man bash (4.2.24):
Quizás la evaluación sobre varios comandos lleva a ignorar el || contexto.
fuente
evaltruco no me funciona. Intenté bash, bash en modo posix y dash.set -e.set -eEstá roto por diseño. No lo usaría para nada más que los scripts de shell más simples sin estructuras de control, subcapas o sustituciones de comandos.Solución alternativa cuando usint toplevel
set -eLlegué a esta pregunta porque estaba usando
set -ecomo método de detección de errores:y sin
||, el script dejaría de ejecutarse y nunca llegaríado_more_stuff.Como parece que no hay una solución limpia, creo que solo haré un simple
set +een mis scripts:fuente