Ich verwende ein herstellerspezifisches Build-Tool (Closed Source, Microsemi Designer, ein FPGA-Layout-Tool). Ich rufe es über ein Shell-Skript auf (stark vereinfacht):
... # Setup
/opt/.../designer SCRIPT:my_script.tcl |tee build.log
... # Postprocessing
Das Problem besteht darin, dass der Prozess auch nach designer
Beendigung tee
weiter ausgeführt wird und das Skript somit nicht fortgesetzt wird.
Soweit ich es verstehe, liegt das daran, dass designer
ein langlebiger Daemon erzeugt wird,
windu_scmd50
und dieser Daemon schließt seine Standardausgabe (die er von erbt designer
) nicht. Daher tee
wartet er auf ein EOF an seiner Standardeingabe (verbunden mit der Pipe), das nie kommt.
Beweise, dass dies die Ursache des Problems ist:
ps
zeigt, dass der Tee-Prozess noch läuft, der Designer-Prozess jedoch nicht.- Wenn ich den
windu_scmd50
Prozess beende,tee
wird er sofort beendet und das Skript wird fortgesetzt (dies kann ich jedoch in der Produktion nicht tun). designer
Wenn ich die Ausgabe von nicht antee
(oder an etwas anderes; das Gleiche passiert mitcat
in anstelle von ) weiterleitetee
, bleibt das Skript nicht hängen.- Wenn ich es
designer
von Jenkins aus ausführe (ohne die Ausgabe in eine Datei umzuleiten), benachrichtigt mich Jenkins, dass der „Prozess durchgesickerte Dateideskriptoren“ mit einer Verknüpfung zu diese Hilfeseite(offenbar befasst sich Jenkins ausdrücklich mit dieser Situation).
Also:Wie kann ich sicherstellen, dass der tee
Prozess gleichzeitig (oder kurz danach) beendet wird designer
?
Einige Ansätze, die ich in Betracht gezogen habe:
- Ist es möglich, die Standardausgabe eines laufenden Prozesses umzuleiten?
- Gibt es ein Tool, das ich anstelle einer Shell-Pipe verwenden kann, um die Beendigung des
designer
Prozesses zu erkennen?
Einige Ansätze, die nicht möglich sind:
- Ich kann die Ausgabe des
designer
Prozesses nicht ignorieren; ich muss sie in eine Protokolldatei schreiben. - Ich kann den Prozess nicht beenden,
windu_scmd50
da er möglicherweise von anderen Prozessen auf dem Computer verwendet wird. - Die aufdie Jenkins-Hilfeseitescheinen nicht zuzutreffen, da sie auch die Ausgabe von stummschalten würden
designer
. - Ich kann die Toolinstallation nicht ändern, um die
windu_scmd50
ausführbare Datei durch einen Wrapper zu ersetzen.
Noch einige Anmerkungen:
- Das Protokollieren der Ausgabe des
windu_scmd50
Prozesses wäre nett, ist aber keine Voraussetzung. Ich muss jedoch die Ausgabe des Designerprozesses protokollieren. - In der Praxis gibt es einen weiteren Filter zwischen
designer
undtee
, der Zeitstempel hinzufügt (designer ... |ts -s |tee build.log
) - Die Verwendung von
bash
-spezifischen Funktionen ist zulässig. Kompatibilität mitsh
ist keine Voraussetzung.
Hier ist ein Minimalbeispiel, das das Problem demonstriert ( test.sh
):
#!/bin/bash
echo "Start"
sleep 10 & # Background process that does not close stdout
echo "End"
Der direkte Aufruf dieses Skripts ( ./test.sh
) gibt „Start“ und „End“ aus und beendet es sofort. Das Weiterleiten der Ausgabe an einen anderen Prozess ( ./test.sh |cat
) gibt „Start“ und „End“ sofort aus, hält dann aber 10 Sekunden inne, bevor es beendet wird.
Antwort1
Eine recht einfache Problemumgehung besteht darin, nach Beendigung des Prozesses eine Nachricht in den Stream einzufügen designer
. Ein cat
vorhergehender -ähnlicher Filter tee
sollte beendet werden, wenn er auf die Nachricht trifft.
Es wird ungefähr so aussehen:
{ /opt/.../designer SCRIPT:my_script.tcl; echo message; } \
| sed -n '/^message$/q;p' | tee build.log
Anmerkungen:
Wenn
designer
(oder irgendetwas, das seine Standardausgabe erbt) die Nachricht ausgibt,sed
wird das Programm vorzeitig beendet. Wählen Sie einsTr1ng_Unlik3ly t0-Be enCOUnTered_in vvhat designer PRinT5
. Das ASCII-EOT-Zeichen (Oktal 004) kann eine gute Wahl sein:
{ …; printf '\004\n'; } | sed -n "/^$(printf '\004')\$/q;p" | …
Es gibt Grenzen für das, was
sed
man bewältigen kann. Siehediese Antwort übergrep
, bei ist es ähnlichsed
.^message$
entspricht einer vollständigen Zeile, diemessage
nur enthält. Dies setzt voraus, dass die Ausgabe (falls vorhanden) desdesigner
Prozesses mit einem Zeilenumbruchzeichen endet (d. h. die letzte Zeile ist vollständig; sieheLinieGegenunvollständige Zeile); nur dannmessage
wird es in einer eigenen Zeile stehen. Wenndesigner
mit Sicherheit eine unvollständige Zeile erzeugt wird, dann wollen Siesed -n '/message$/{s/message$//;p;q};p'
. Wenn es in beide Richtungen gehen kann, dann wollen Siesed -n '/^message$/q;/message$/{s/message$//;p;q};p'
. Beachten Sie, dass die unvollständige Zeile vondesigner
zu einer vollständigen Zeile wird.Nicht-stumme Nachkommen von
designer
können stören:- Sie können dazu führen,
message
dass eine Zeile in der Mitte erscheint (selbst wenn sie versuchen, vollständige Zeilen auszugeben). Für unssed
wird es so sein, als obdesigner
eine unvollständige Zeile generiert wurde. - Wenn die von Ihnen gewählte Nachricht sehr lang ist, wird sie möglicherweise in der Pipe mit anderen Daten verschachtelt angezeigt (siehediese AntwortUnd
PIPE_BUF
Hier). In diesem Fallsed
wird es von uns überhaupt nicht erkannt.
- Sie können dazu führen,