Estoy usando una herramienta de compilación específica del proveedor (de código cerrado) (Microsemi Designer, una herramienta de diseño de FPGA). Lo invoco desde un script de shell (muy simplificado):
... # Setup
/opt/.../designer SCRIPT:my_script.tcl |tee build.log
... # Postprocessing
El problema es: incluso después de que designer
finaliza el proceso, el tee
proceso continúa ejecutándose y, por lo tanto, el script no continúa.
Hasta donde tengo entendido, esto se debe a que designer
genera un demonio de larga duración,
windu_scmd50
y ese demonio no cierra su salida estándar (de la que hereda designer
). También tee
está esperando un EOF en su entrada estándar (conectada a la tubería) que nunca llega.
Evidencia de que esta es la causa del problema:
ps
muestra que el proceso de tee todavía se está ejecutando, pero el proceso de diseñador no.- Cuando cierro el
windu_scmd50
proceso,tee
finaliza inmediatamente y el script continúa (pero no puedo hacer esto en producción). - Si no canalizo la salida de
designer
totee
(o cualquier otra cosa; sucede lo mismo concat
en lugar detee
), el script no se detiene. - Si ejecuto
designer
desde Jenkins (sin canalizar la salida a un archivo), Jenkins me notifica que los "Descriptores de archivos filtrados del proceso", que vinculan a esta página de ayuda(aparentemente, Jenkins se ocupa explícitamente de esta situación).
Entonces:¿Cómo puedo asegurarme de que el tee
proceso finalice cuando (o poco después) designer
lo haga?
Algunos enfoques que he considerado:
- ¿Es posible redirigir la salida estándar de un proceso en ejecución?
- ¿Existe alguna herramienta que pueda usar en lugar de un shell pipe que detecte la terminación del
designer
proceso?
Algunos enfoques que no son posibles:
- No puedo ignorar el resultado del
designer
proceso; Necesito escribirlo en un archivo de registro. - No puedo finalizar el
windu_scmd50
proceso porque podría ser utilizado por otros procesos en la máquina. - Las soluciones descritas enla página de ayuda de Jenkinsno parecen aplicarse porque también silenciarían la salida de
designer
. - No puedo modificar la instalación de la herramienta para reemplazar el
windu_scmd50
ejecutable con un contenedor.
Algunas notas más:
windu_scmd50
Sería bueno registrar el resultado del proceso, pero no es un requisito. Sin embargo, necesito registrar el resultado del proceso de diseñador.- En la práctica, existe otro filtro entre
designer
ytee
que agrega marcas de tiempo (designer ... |ts -s |tee build.log
) - Es aceptable utilizar
bash
funciones específicas; la compatibilidad consh
no es un requisito
A continuación se muestra un ejemplo mínimo que demuestra el problema ( test.sh
):
#!/bin/bash
echo "Start"
sleep 10 & # Background process that does not close stdout
echo "End"
Al llamar a este script directamente ( ./test.sh
), se imprimen "Inicio" y "Fin" y finaliza inmediatamente. Al canalizar la salida a otro proceso ( ./test.sh |cat
), se imprimen "Inicio" y "Fin" inmediatamente, pero luego se detiene durante 10 segundos antes de finalizar.
Respuesta1
Una solución bastante sencilla es inyectar un mensaje en la secuencia una vez designer
finalizado el proceso. Un cat
filtro similar al anterior tee
debería salir cuando encuentre el mensaje.
Será algo como:
{ /opt/.../designer SCRIPT:my_script.tcl; echo message; } \
| sed -n '/^message$/q;p' | tee build.log
Notas:
Si
designer
(o cualquier cosa que herede su salida estándar) imprime el mensaje,sed
se cerrará prematuramente. Escoge unsTr1ng_Unlik3ly t0-Be enCOUnTered_in vvhat designer PRinT5
. El carácter ASCII EOT (octal 004) puede ser una buena opción:
{ …; printf '\004\n'; } | sed -n "/^$(printf '\004')\$/q;p" | …
Hay límites a lo que
sed
se puede manejar. Veresta respuesta sobregrep
, es similar consed
.^message$
coincide con una línea completa que contienemessage
únicamente. Esto supone que la salida (si la hay) deldesigner
proceso termina con un carácter de nueva línea (es decir, la última línea está completa; consultelíneavslinea incompleta); sólo entoncesmessage
estará en su propia línea. Sidesigner
genera una línea incompleta, entonces seguramente querrássed -n '/message$/{s/message$//;p;q};p'
. Si puede ser de cualquier manera, entonces quieressed -n '/^message$/q;/message$/{s/message$//;p;q};p'
. Tenga en cuenta que la línea incompleta dedesigner
se convertirá en una línea completa.Los descendientes no silenciosos de
designer
pueden interferir:- Pueden hacer
message
que aparezcan en la mitad de la línea (incluso si intentan generar líneas completas). Para nuestrosed
será como si sedesigner
generara una línea incompleta. - Si el mensaje elegido es muy largo, es posible que aparezca en el canal intercalado con otros datos (consulteesta respuestay
PIPE_BUF
aquí). En tal caso,sed
no lo detectaremos en absoluto.
- Pueden hacer