与えられた壁時間だけ持続するパイプを作る簡単な方法はありますか?
時間が経つにつれて、STDOUTに記録されている内容(バイトや行ではない)の「スナップショット」を撮ることができるようにしたいです。それはまるで
tail -f /var/log/whatever.log | pipe_for_seconds 10 > ./10_second_sample_of_log
私はBASHを使用していますが、他のシェルでこれがより簡単な場合はこれについて聞きたいです。
答え1
ゲヌコアツールバージョン7.0以降、次のコマンドがありますtimeout
。
timeout 10 tail -f /var/log/whatever.log
もしあなたなら本物わずかに異なるプロセスをタイムアウトしてからパイプを接続するには、パイプが必要ですtimeout
。
tail -f /var/log/whatever.log | timeout 10 cat > ./10_second_sample_of_log
しかし、参考にしてくださいパイプラインの一部を終了すると、バッファリングによって問題が発生する可能性があります。、信号、およびプログラムの動作によって異なります(この質問は関連する問題をカバーしています。パイプラインでバッファリングをオフにする)。通常変わります。終了コード過程も同じだ。
(最近)coreutilsがないと、この単純なタイムアウトプログラムもうまく機能します。 http://www.unixlabplus.com/unix-prog/timeout/timeout.html またはパール方法:
tail -f /var/log/whatever.log | perl -n -e 'BEGIN{alarm 10; $|=1}; print;'
(注:$|=1
出力バッファリングはオフになります。これは上記のようにパイプ内の出力損失を防ぐためです。)
(少し年をとった)ネットワークパイプパッケージにはtimelimit
コマンドもあります(一部のLinuxシステムではまだ見つかります)。
この同様の質問にはいくつかのオプションがあります。シェルスクリプトにタイムアウトを導入する方法は?
答え2
これは働きます:
tail -f /var/log/whatever.log > ten_second_sample & sleep 10 && kill $!
tail
sleep
10秒間バックグラウンドで並列に開始以来 kill
$!
最後に開始されたバックグラウンドプロセスのPID。
答え3
tail -f
PID の終了に依存することは、PID が早すぎる(たとえば、ファイルが存在しない場合など)、信頼できない可能性があります。もう1つのより一般的な解決策は、タイムアウトの前に「キルタイマー」が完了すると、andの使用も中止wait
されますkill %%
(%%
bashで始まった最新の操作 - usingの使用を意味します&
)。
設定は次のとおりです(sleep 2
パラメータなどを含むカスタムコマンドがあり、タイムアウトが10秒に設定されています)。
# Your command that may take some (or not) time to execute:
sleep 2 &
# Set a timer that kills the last started job
sleep 10 & wait -n 1; kill %%; wait -n 1
この設定は、タイムアウトに達するか、カスタムコマンドが実行を完了するのを待ちます(この場合は常にsleep 2
最初に停止します)。これにより、コマンドまたはタイムアウトがそれぞれ終了しますkill %%
。最後のコマンドは、wait -n 1
コマンドまたはタイムアウトが実際に終了するまで追加の実行をブロックします(オプションですが必須です)。
メモ。必要で予期したとおり、以前に並列に実行されたコマンドは影響を受けません。
はい
read
タイムアウトのある名前付きパイプから行を読み取るがタイムアウトフラグを使用しないより実用的な例:
# Custom bash function to set timeout in seconds for the most recently started job (parallel execution).
timeout() { sleep $1 & wait -n 1; kill %%; wait -n 1 }
# Example 1:
mkfifo /tmp/test
read ln </tmp/test &
timeout 10
何も記録されないため、/tmp/test
10秒後にタイムアウトします。コマンドがすぐに終了しても終了タイマーが停止することを示すために:
# Example 2:
mkfifo /tmp/test
echo "Hello" >/tmp/test &
ln="$(read ln </tmp/test && echo -e "$ln" & timeout 10)"
echo "Line was read: $ln"
名前付きパイプの実際の使用に注意してください。サブシェルで実行されるため、read ln
(親)スクリプトからはアクセスできません。したがって、echo
(他の)変数に保存するために行が印刷されますln
。