segfaultプログラムのパイプ出力

segfaultプログラムのパイプ出力

プログラム(特にtetex 3.0の一部)を呼び出すスクリプトがあり、ttf2afm時にはセグフォルトが発生し、時にはそうではありません。私に必要な情報は常に印刷されています。今後セグメントは発生しますが、パイプリダイレクトが失敗するのを防ぎ、プログラムが失敗したときにパイプに何も出力しないのに問題があります。

trueFIFOを介してリダイレクトしようとしましたが、最後にプロセスをラップし、シェル関数で実行してからラップしましたが、スクリプトはsh -cプロセス出力を受け入れないようです。何もない、リダイレクトやその他 - stderrではありません。

私はそれがコマンドラインから完全に提供できるので出力できることを知っていますが、何らかの理由でスクリプトでは提供できません。

私の質問は、スクリプトがセグフォルトの事実を無視して出力を提供できる方法はありますか?

BASH 4.1.10(2) リリースを実行しています。

答え1

プログラムは、効率を高めるために出力をバッファリングすることがよくあります。つまり、メモリ領域(バッファと呼ばれる)に出力を蓄積し、バッファがいっぱいになったときやプログラムの特定の重要なポイントでのみ実際に出力を出力します。プログラムが正常に終了したら、出力バッファをフラッシュします(つまり、バッファに残っているすべてのデータを印刷します)。セグフォルトが発生すると、バッファの内容が失われます。

プログラムの出力がターミナルに接続されている場合(通常のファイルやパイプではない)動作が異なるため、ターミナルで直接プログラムを実行すると、この効果は観察できません。端末でのデフォルト動作は、各行の終わりにバッファをフラッシュすることです。したがって、セグメントエラーが発生する前にプログラムによって生成されたすべての行を表示できます。

プログラムを端末で強制的に実行し、その出力を収集できます。最も簡単な方法は走ることですscript。解決すべき心配がたくさんあります。

  • script後で削除する必要があるヘッダー行を転写ファイルに追加します。
  • scriptコマンドのステータスコードは返されないため、segfaultやその他のエラーについて知りたい場合は、どこかに保存する必要があります。
  • script通常出力とエラー出力の両方が発生します。エラー出力を別々のファイルに保存することをお勧めします。
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

答え2

続けてたどり着いた後、ついに調べました。解決策は少し複雑です。

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

どうやらサブシェルプロセスをexec捕捉したエラーがttf2afm引き継がれ、セグフォルトが発生するかどうかが重要でない環境で実行されるようになったようです。

包括的なシグナルをキャプチャすると、サブシェルが死ぬのを防ぎ、プログラムが失敗したときにERRメインスクリプトにシグナルを送信します(これが発生すると、メインスクリプトはすぐに終了します)。

唯一の問題はカーネル自体スタックトレースごみを出力しますコンソールデバイスに直接接続プロセスセグフォルトが発生すると、[私が知る限り]出力されるのを防ぐ方法はありませんが、stdoutやstderrには影響しないので問題になりません。

関連情報