La herramienta de compilación genera un demonio que no cierra su salida estándar. ¿Cómo puedo evitar que esto detenga mi canalización de shell?

La herramienta de compilación genera un demonio que no cierra su salida estándar. ¿Cómo puedo evitar que esto detenga mi canalización de shell?

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 designerfinaliza el proceso, el teeproceso continúa ejecutándose y, por lo tanto, el script no continúa.

Hasta donde tengo entendido, esto se debe a que designergenera un demonio de larga duración, windu_scmd50y ese demonio no cierra su salida estándar (de la que hereda designer). También teeestá 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:

  • psmuestra que el proceso de tee todavía se está ejecutando, pero el proceso de diseñador no.
  • Cuando cierro el windu_scmd50proceso, teefinaliza inmediatamente y el script continúa (pero no puedo hacer esto en producción).
  • Si no canalizo la salida de designerto tee(o cualquier otra cosa; sucede lo mismo con caten lugar de tee), el script no se detiene.
  • Si ejecuto designerdesde 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 teeproceso finalice cuando (o poco después) designerlo 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 designerproceso?

Algunos enfoques que no son posibles:

  • No puedo ignorar el resultado del designerproceso; Necesito escribirlo en un archivo de registro.
  • No puedo finalizar el windu_scmd50proceso 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_scmd50Serí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 designery teeque agrega marcas de tiempo ( designer ... |ts -s |tee build.log)
  • Es aceptable utilizar bashfunciones específicas; la compatibilidad con shno 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 designerfinalizado el proceso. Un catfiltro similar al anterior teedeberí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, sedse cerrará prematuramente. Escoge un sTr1ng_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 sedse puede manejar. Veresta respuesta sobregrep, es similar con sed.

  • ^message$coincide con una línea completa que contiene messageúnicamente. Esto supone que la salida (si la hay) del designerproceso termina con un carácter de nueva línea (es decir, la última línea está completa; consultelíneavslinea incompleta); sólo entonces messageestará en su propia línea. Si designergenera una línea incompleta, entonces seguramente querrás sed -n '/message$/{s/message$//;p;q};p'. Si puede ser de cualquier manera, entonces quieres sed -n '/^message$/q;/message$/{s/message$//;p;q};p'. Tenga en cuenta que la línea incompleta de designerse convertirá en una línea completa.

  • Los descendientes no silenciosos de designerpueden interferir:

    • Pueden hacer messageque aparezcan en la mitad de la línea (incluso si intentan generar líneas completas). Para nuestro sedserá como si se designergenerara una línea incompleta.
    • Si el mensaje elegido es muy largo, es posible que aparezca en el canal intercalado con otros datos (consulteesta respuestayPIPE_BUFaquí). En tal caso, sedno lo detectaremos en absoluto.

información relacionada