私は(クローズドソースの)ベンダー固有のビルド ツール(Microsemi Designer、FPGA レイアウト ツール)を使用しています。これをシェル スクリプト(非常に簡略化)から呼び出します。
... # Setup
/opt/.../designer SCRIPT:my_script.tcl |tee build.log
... # Postprocessing
問題は、designer
プロセスが終了した後もtee
プロセスが実行し続け、スクリプトが続行されないことです。
私の理解する限りでは、これは がdesigner
長寿命デーモン を生成し
windu_scmd50
、そのデーモンが標準出力 ( から継承designer
) を閉じないためです。 は、tee
決して到達しない標準入力 (パイプに接続) の EOF を待機しているためです。
これが問題の原因であるという証拠:
ps
ティー プロセスはまだ実行中ですが、デザイナー プロセスは実行されていないことがわかります。- プロセスを強制終了すると
windu_scmd50
、tee
すぐに終了し、スクリプトは続行されます (ただし、本番環境ではこれを実行できません)。 designer
の出力を にパイプしない場合(または他の場所にパイプしない場合。 の代わりにtee
を使用した場合も同じことが起こります)、スクリプトは停止しません。cat
tee
- Jenkinsから実行すると
designer
(出力をファイルにパイプせずに)、Jenkinsは「プロセスがファイル記述子を漏らした」と通知し、 このヘルプページ(どうやら、Jenkins はこの状況に明示的に対処しているようです)。
それで:tee
プロセスが終了したとき(または直後に)プロセスが終了することを保証するにはどうすればよいですかdesigner
?
私が検討したいくつかのアプローチ:
- 実行中のプロセスの stdout をリダイレクトすることは可能ですか?
- シェル パイプの代わりに使用して、プロセスの終了を検出できるツールはありますか
designer
?
不可能なアプローチ:
- プロセスからの出力を無視することはできません
designer
。ログ ファイルに書き込む必要があります。 windu_scmd50
マシン上の他のプロセスによって使用されている可能性があるため、プロセスを強制終了できません。- で説明した回避策はJenkinsヘルプページからの出力も無音になるため、適用されないようです
designer
。 - ツールのインストールを変更して
windu_scmd50
実行可能ファイルをラッパーに置き換えることはできません。
その他の注意事項:
- プロセスからの出力をログに記録するのは
windu_scmd50
良いことですが、必須ではありません。ただし、デザイナー プロセスからの出力はログに記録する必要があります。 designer
実際には、との間にタイムスタンプを追加する別のフィルタがありますtee
(designer ... |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
非常に簡単な回避策は、プロセスが終了した後にストリームにメッセージを挿入することですdesigner
。cat
先行する -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
はまったく検出できません。