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 -utambié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 lectorpipeporque es el shell el que hace el comandoopen()y, en cuanto haya un lector enpipeel enlace fs parapipeisrm'd, y luegocatcopie 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
SIGTERMd antes de que se pueda ejecutar el segundo comando (other_command). Elecho okcomando 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 okcomando. 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
echocomandos pudieran escribir en el descriptor de archivo. En el segundo, elfalseo elkillcomando probablemente se programaron después de losechocomandos.O para ser más precisos: la llamada al sistema
signal()de lakillutilidad que envía laSIGTERMseñ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
killjunto contrap.Pero
killno puede pasar un código de retorno de su subproceso al proceso padre.fuente
De manera similar a como implementaría
$PIPESTATUS/$pipestatuscon 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
pipefaile implementar la sustitución de procesos a mano como lo haría con shells que no lo admiten:fuente