Me gustaría hacer un pipeline de scripts de Bash como este
prog1 | prog2
tal que prog2 puede ver el código de salida de prog1 y actuar de manera diferente en función de esa información.
es posible?
La respuesta general es no. Es posible prog2
salir antes prog1
incluso de comenzar (obviamente, eso no puede suceder si prog2
realmente lee alguna entrada, lo que esperaría que hiciera si lo está usando en una tubería). Definitivamente es posible prog2
salir antes prog1
; Esto sucede, por ejemplo, cuando se prog2
trata de un programa de búsqueda que sale tan pronto como encuentra una coincidencia, en cuyo caso prog1
puede que todavía no haya terminado de producir todos los datos.
No hay una forma directa de prog2
recuperar el estado de salida prog1
o incluso saber que prog1
ha salido. Todo lo que prog2
puede saber es que prog1
ha cerrado su extremo de la tubería, lo que puede hacer sin morir.
Si desea obtener el estado de salida prog1
de prog2
, hay dos métodos comunes: se puede escribir en un archivo, o se puede enviar a través de la tubería. Enviar el estado de salida como la última línea de los datos canalizados es una posibilidad. Debe asegurarse de no procesar la última línea hasta que sepa que es la última línea, es decir, hasta que haya intentado leer la siguiente.
{ prog1; echo $?; } | …
Aquí hay un ejemplo donde el lado derecho es un filtro de texto que colorea cada línea que contiene la palabra "error" en rojo. Si el lado izquierdo falla, el lado derecho sale con el mismo estado.
{ prog1; echo $?; } | awk '
NR != 1 {
if (line ~ /[Ee][Rr][Rr][Oo][Rr]/) print "\033[31m" line "\033[0m";
else print line;
}
{line = $0}
END {exit($0)}
'
{ command; echo ${PIPESTATUS[@]}; } | sort | ...
para que el estado de salida venga primero en la secuencia. ¡Todo es muy interesante!
${PIPESTATUS[@]}
se ordena antes que cualquier otra cosa en la salida de command
. Si command
imprime varios números, o si puede imprimir texto arbitrario, tiene problemas: no podrá distinguir su salida de la línea de estado.
Aunque puede en algunos casos especiales (vea las otras respuestas) no puede en todos los casos. Algunos programas de filtro simplemente continuarán, mientras que otros mantendrán toda la salida, la desatarán de una sola vez y luego saldrán.
Para un ejemplo de un programa "simplemente continúe", grep
servidor, como lo haría tail -f /var/log/some_log_file
. El uso sort
en una tubería provoca un "bloqueo", ya sort
que recogerá la entrada hasta que la tubería frente a ella se cierre. El uso xargs
agrega una complicación adicional: ¿son los programas iniciados por xargs
(puede comenzar muchas instancias) parte de la tubería o no?
La respuesta: no directamente.
@terdon ha ilustrado que el código de salida del comando anterior en la tubería debe enviarse como un parámetro explícito al siguiente comando.
Recuerde que la tubería es simplemente un mapeo del STDOUT del comando anterior al STDIN del siguiente comando; los códigos de salida no se envían a STDOUT (o STDERR).
Todos los procesos, en proceso, se inician antes de cualquier salida. Por prog2
lo tanto, podría tener que obtener esta información después de que haya comenzado, también tendría que retrasar el procesamiento hasta que prog1
haya salido, esto podría detener la tubería. Parece haber problemas fundamentales al hacer lo que pides, no limitaciones del sistema operativo.
Probablemente deba considerar un archivo temporal o colocar el resultado en una variable.
Ejemplo para una pequeña cantidad de datos, usando una variable.
tmp=$(prog1)
if test "z$PIPESTATUS" == "z0"
then
…
else
…
fi
prog2
se inicia antes de que se prog1
complete en general, pero podría haber una forma de recibir el estado de salida prog1
mientras se está ejecutando.
Para terminar la respuesta de Gilles ,
(prog1; echo $? > /tmp/prog1.status) | prog2
Es un enfoque. prog2
podría
/tmp/prog1.status
, o/tmp/prog1.status
periódicamente mientras lee la entrada estándar.
prog2
ha progresado cuandoprog1
sale, debido al almacenamiento en búfer interno utilizado para implementar la tubería y cómoprog1
y cómoprog2
están programados.