Quiero que mis scripts de shell fallen siempre que un comando ejecutado con ellos falle.
Típicamente hago eso con:
set -e
set -o pipefail
(normalmente agrego set -u
también)
El caso es que ninguno de los anteriores funciona con la sustitución de procesos. Este código imprime "ok" y sale con el código de retorno = 0, mientras que me gustaría que fallara:
#!/bin/bash -e
set -o pipefail
cat <(false) <(echo ok)
¿Hay algo equivalente a "pipefail" pero para la sustitución del proceso? ¿Hay alguna otra forma de pasar a un comando la salida de comandos como si fueran archivos, pero generar un error cada vez que falla alguno de esos programas?
La solución de un hombre pobre sería detectar si esos comandos escriben en stderr (pero algunos comandos escriben en stderr en escenarios exitosos).
Otra solución más compatible con posix sería usar canalizaciones con nombre, pero necesito eliminar esos comandos que utilizan la sustitución de procesos como líneas integradas sobre la marcha a partir de código compilado, y crear canalizaciones con nombre complicaría las cosas (comandos adicionales, error de captura para eliminándolos, etc.)
fuente
mkfifo pipe; { rm pipe; cat <file; } >pipe
. Ese comando se bloqueará hasta que se abra un lectorpipe
porque es el shell el que hace el comandoopen()
y, en cuanto haya un lector enpipe
el enlace fs parapipe
isrm
'd, y luegocat
copie el archivo en el descriptor del shell para ese conducto. Y de todos modos, si desea propagar un error fuera de un subproceso de proceso: <( ! : || kill -2 "$$")
$$
sustitución no funciona para mí, ya que la sustitución de este comando no se realiza ya que el comando que utiliza la sustitución del proceso se realiza dentro de una tubería de comando que se genera a partir de un código "no shell" (python). Probablemente debería crear un subproceso en python y canalizarlos programáticamente.kill -2 0
.Respuestas:
Solo podría solucionar ese problema con eso, por ejemplo:
La subshell del script es
SIGTERM
d antes de que se pueda ejecutar el segundo comando (other_command
). Elecho ok
comando se ejecuta "a veces": el problema es que las sustituciones de proceso son asíncronas. No hay garantía de que elkill $$
comando se ejecute antes o después delecho ok
comando. Se trata de la programación de los sistemas operativos.Considere un script bash como este:
El resultado de ese script puede ser:
O:
Puede probarlo y después de algunos intentos, verá las dos órdenes diferentes en la salida. En el primero, el script finalizó antes de que los otros dos
echo
comandos pudieran escribir en el descriptor de archivo. En el segundo, elfalse
o elkill
comando probablemente se programaron después de losecho
comandos.O para ser más precisos: la llamada al sistema
signal()
de lakill
utilidad que envía laSIGTERM
señal al proceso de shells se programó (o se entregó) más tarde o antes que laswrite()
llamadas de sistema de eco .Sin embargo, el script se detiene y el código de salida no es 0. Por lo tanto, debería resolver su problema.
Otra solución es, por supuesto, utilizar tuberías con nombre para esto. Pero, depende de su secuencia de comandos lo complejo que sería implementar canalizaciones con nombre o la solución anterior.
Referencias
fuente
Para el registro, e incluso si las respuestas y comentarios fueron buenos y útiles, terminé implementando algo un poco diferente (tenía algunas restricciones sobre la recepción de señales en el proceso principal que no mencioné en la pregunta)
Básicamente, terminé haciendo algo como esto:
Luego verifico el archivo de error. Si existe, sé qué subcomando falló (y el contenido del archivo de error puede ser útil). Más detallado y hackeo de lo que originalmente quería, pero menos engorroso que crear tuberías con nombre en un comando bash de una sola línea.
fuente
Este ejemplo muestra cómo usar
kill
junto contrap
.Pero
kill
no puede pasar un código de retorno de su subproceso al proceso padre.fuente
De manera similar a como implementaría
$PIPESTATUS
/$pipestatus
con un shell POSIX que no lo admite , puede obtener el estado de salida de los comandos pasándolos a través de una tubería:Lo que da:
O puede usar
pipefail
e implementar la sustitución de procesos a mano como lo haría con shells que no lo admiten:fuente