ビルド ツールは、標準出力を閉じないデーモンを生成します。これがシェル パイプラインを停止させないようにするにはどうすればよいですか?

ビルド ツールは、標準出力を閉じないデーモンを生成します。これがシェル パイプラインを停止させないようにするにはどうすればよいですか?

私は(クローズドソースの)ベンダー固有のビルド ツール(Microsemi Designer、FPGA レイアウト ツール)を使用しています。これをシェル スクリプト(非常に簡略化)から呼び出します。

...  # Setup

/opt/.../designer SCRIPT:my_script.tcl |tee build.log

...  # Postprocessing

問題は、designerプロセスが終了した後もteeプロセスが実行し続け、スクリプトが続行されないことです。

私の理解する限りでは、これは がdesigner長寿命デーモン を生成し windu_scmd50、そのデーモンが標準出力 ( から継承designer) を閉じないためです。 は、tee決して到達しない標準入力 (パイプに接続) の EOF を待機しているためです。

これが問題の原因であるという証拠:

  • psティー プロセスはまだ実行中ですが、デザイナー プロセスは実行されていないことがわかります。
  • プロセスを強制終了するとwindu_scmd50teeすぐに終了し、スクリプトは続行されます (ただし、本番環境ではこれを実行できません)。
  • designerの出力を にパイプしない場合(または他の場所にパイプしない場合。 の代わりにteeを使用した場合も同じことが起こります)、スクリプトは停止しません。cattee
  • Jenkinsから実行するとdesigner(出力をファイルにパイプせずに)、Jenkinsは「プロセスがファイル記述子を漏らした」と通知し、 このヘルプページ(どうやら、Jenkins はこの状況に明示的に対処しているようです)。

それで:teeプロセスが終了したとき(または直後に)プロセスが終了することを保証するにはどうすればよいですかdesigner?

私が検討したいくつかのアプローチ:

  • 実行中のプロセスの stdout をリダイレクトすることは可能ですか?
  • シェル パイプの代わりに使用して、プロセスの終了を検出できるツールはありますかdesigner?

不可能なアプローチ:

  • プロセスからの出力を無視することはできませんdesigner。ログ ファイルに書き込む必要があります。
  • windu_scmd50マシン上の他のプロセスによって使用されている可能性があるため、プロセスを強制終了できません。
  • で説明した回避策はJenkinsヘルプページからの出力も無音になるため、適用されないようですdesigner
  • ツールのインストールを変更してwindu_scmd50 実行可能ファイルをラッパーに置き換えることはできません。

その他の注意事項:

  • プロセスからの出力をログに記録するのはwindu_scmd50良いことですが、必須ではありません。ただし、デザイナー プロセスからの出力はログに記録する必要があります。
  • designer実際には、との間にタイムスタンプを追加する別のフィルタがありますteedesigner ... |ts -s |tee build.log
  • bash固有の機能の使用は許容されますが、 との互換性shは必須ではありません。

問題を示す最小限の例を次に示します ( test.sh)。

#!/bin/bash
echo "Start"
sleep 10 &    # Background process that does not close stdout
echo "End"

このスクリプトを直接呼び出すと ( ./test.sh)、「Start」と「End」が出力され、すぐに終了します。出力を別のプロセスにパイプすると ( ./test.sh |cat)、「Start」と「End」がすぐに出力されますが、終了する前に 10 秒間一時停止します。

答え1

非常に簡単な回避策は、プロセスが終了した後にストリームにメッセージを挿入することですdesignercat先行する -like フィルターは、teeメッセージに遭遇すると終了する必要があります。

それは次のようになります:


{ /opt/.../designer SCRIPT:my_script.tcl; echo message; } \
| sed -n '/^message$/q;p' | tee build.log

ノート:

  • designer(または標準出力を継承するもの) がメッセージを出力すると、sed途中で終了します。 を選択してくださいsTr1ng_Unlik3ly t0-Be enCOUnTered_in vvhat designer PRinT5。ASCII EOT 文字 (8 進数 004) が適切な選択かもしれません。
    { …; printf '\004\n'; } | sed -n "/^$(printf '\004')\$/q;p" | …

  • sed処理できる範囲には限界があります。この答えについてgrep、 と似ていますsed

  • ^message$のみを含む完全な行に一致しますmessage。これは、プロセスからの出力(ある場合)がdesigner改行文字で終了することを前提としています(つまり、最後の行は完全です。ライン不完全な行); の場合のみ、 はmessage独自の行になります。 がdesigner確実に不完全な行を生成する場合は、 が必要ですsed -n '/message$/{s/message$//;p;q};p'。 どちらの方法でもよい場合は、 が必要ですsed -n '/^message$/q;/message$/{s/message$//;p;q};p'。 からの不完全な行はdesigner完全な行になることに注意してください。

  • の非サイレント子孫がdesigner干渉する可能性があります:

    • message完全な行を出力しようとしても、行の途中に現れることがあります。私たちにとっては、不完全な行が生成されたsedかのようになります。designer
    • 選択したメッセージが非常に長い場合は、パイプ内で他のデータと交互に表示されることがあります(この答えそしてPIPE_BUFここ)。そのような場合、弊社でsedはまったく検出できません。

関連情報