Piping-Ausgabe eines Segfault-Programms

13

Ich habe ein Skript, das ein Programm aufruft (speziell einen ttf2afmTeil von Tetex 3.0), das manchmal fehlerhaft ist und manchmal nicht. Die Informationen, die ich benötige, werden immer ausgedruckt, bevor sie sich als fehlerhaft herausstellen. Es fällt mir jedoch schwer, die Pipe-Umleitung daran zu hindern, fehlzuschlagen, und nichts an die Pipe auszugeben, wenn das Programm fehlschlägt.

Ich habe versucht, durch ein FIFO umzuleiten, den Prozess mit einem trueam Ende in Klammern zu setzen , von einer Shell-Funktion aus auszuführen und einzufügen sh -c, aber das Skript scheint nie zuzulassen, dass der Prozess etwas ausgibt , umgeleitet oder auf andere Weise - nicht einmal zu stderr.

Ich weiß, dass es zur Ausgabe fähig ist, da es perfekt in der Lage ist, es über die Befehlszeile, aber aus irgendeinem Grund nicht über ein Skript auszugeben.

Meine Frage ist, gibt es eine Möglichkeit für das Skript, die Tatsache, dass das Programm segfaults und geben Sie mir die Ausgabe trotzdem zu ignorieren?

Ich verwende ein BASH 4.1.10 (2) -Release.

Amphetamachine
quelle

Antworten:

12

Programme puffern normalerweise ihre Ausgabe aus Effizienzgründen. Das heißt, sie akkumulieren die Ausgabe in einem Speicherbereich (Puffer genannt) und geben sie tatsächlich nur aus, wenn der Puffer voll ist oder an bestimmten wichtigen Punkten im Programm. Wenn das Programm normal beendet wird, wird der Ausgabepuffer geleert (dh es werden alle Daten ausgedruckt, die darin verbleiben). Wenn der Fehler auftritt, geht der Inhalt des Puffers verloren.

Dieser Effekt tritt nicht auf, wenn Sie das Programm direkt in einem Terminal ausführen, da das Verhalten anders ist, wenn die Programmausgabe mit einem Terminal verbunden ist (im Gegensatz zu einer regulären Datei oder einer Pipe). In einem Terminal wird standardmäßig der Puffer am Ende jeder Zeile geleert. Daher sehen Sie jede vollständige Zeile, die bis zu dem Zeitpunkt produziert wurde, an dem das Programm segfaults.

Sie können das Programm zwingen, in einem Terminal ausgeführt zu werden und dessen Ausgabe zu erfassen. Der einfachste Weg ist zu laufen script. Es gibt eine Reihe von Ärgernissen, die Sie umgehen müssen:

  • script Fügt der Transkriptdatei eine Kopfzeile hinzu, die Sie anschließend entfernen müssen.
  • script Gibt den Statuscode des Befehls nicht zurück. Sie müssen ihn also irgendwo speichern, wenn Sie Informationen zum Segfault oder zu einem anderen Fehler benötigen.
  • scriptVerursacht normale Ausgabe und fehlerhafte Ausgabe. Sie sollten die Fehlerausgabe in einer separaten Datei speichern.
export FONT="foo"
script -q -c '
    ttf2afm "$FONT.ttf" 2>"$FONT.ttf2afm-err";
    echo $? >"$FONT.ttf2afm-status"
' "$FONT.ttf2afm-typescript"
tail -n +2 <"$FONT.ttf2afm-typescript" >"foo.afm"
rm "$FONT.ttf2afm-typescript"
if [ "$(cat "$FONT.ttf2afm-status")" -ne 0 ]; then
  echo 1>&2 "Warning: ttf2afm failed"
  cat "$FONT.ttf2afm-err"
fi
Gilles 'SO - hör auf böse zu sein'
quelle
Gibt es nicht eine elegantere Lösung, wie eine Shell-Einstellung, die den Ausgabepuffer auf 0 setzt oder so?
Amphetamachine
4

Ich habe es schließlich durch Ausprobieren herausgefunden. Die Lösung ist irgendwie verworren:

(trap 'true' ERR; exec ttf2afm "$FONT") |
grep ...

Anscheinend sind die execUrsachen dafür ttf2afm, dass der Subshell-Prozess mit dem eingeschlossenen Fehler übernommen wird und in einer Umgebung ausgeführt wird, in der es unerheblich ist, ob ein Fehler auftritt oder nicht.

Durch ERRdas Fangen des All-Inclusive- Signals wird verhindert, dass die Subshell abstirbt und ein Signal an das Hauptskript sendet, das sofort beendet wird, wenn das Programm fehlschlägt.

Das einzige Problem ist, dass der Kernel selbst eine ganze Reihe von Stack-Trace- Abfällen direkt auf dem Konsolengerät ausgibt, sobald der Prozess fehlerhaft abläuft. Es gibt also keine Möglichkeit, die Ausgabe zu verhindern [von der ich weiß], aber das spielt keine Rolle da es nicht stdout oder stderr betrifft.

Amphetamachine
quelle
3
Ich bin froh, dass dies für Sie funktioniert, aber ich kann zuversichtlich behaupten, dass der Grund dafür nicht darin liegt, dass bash die Ausgabepuffergröße auf 0 setzt. Bash kann die von ttf2afmdirekt verwendete Pufferung nicht beeinflussen . Ich frage mich, wie es (trap true ERR; exec ttf2afm "$FONT")| …gelingt, sich anders zu verhalten als ttf2afm "$FONT" | ….
Gilles 'SO- hör auf böse zu sein'