tail -f を実行し、一致する文字列で終了する

tail -f を実行し、一致する文字列で終了する

私は、tomcat を起動し、catalina.out で文字列 "Server startup" を監視し、別のプロセスを実行する起動スクリプトを設定しようとしています。tail -f と grep および awk のさまざまな組み合わせを試していますが、まだ何も機能していません。私が抱えている主な問題は、grep または awk が文字列に一致した後に tail を強制的に終了させることにあるようです。

次のテストケースに簡略化しました。

test.sh is listed below:

#!/bin/sh    
rm -f child.out
./child.sh > child.out &
tail -f child.out | grep -q B

child.sh is listed below:

#!/bin/sh
echo A
sleep 20
echo B
echo C
sleep 40
echo D

私が見ている動作は、grep は 20 秒後に終了しますが、tail が終了するまでさらに 40 秒かかるというものです。なぜこのようなことが起こるのかは理解しています。tail は、パイプへの書き込み時にパイプがなくなったことに気づくだけであり、これはファイルにデータが追加されるときにのみ発生します。tail はデータをバッファリングし、B 文字と C 文字を 1 回の書き込みとして出力する必要があるという事実によって、この問題はさらに複雑になります (strace で確認しました)。unbuffer コマンドを使用するなど、他の場所で見つけた解決策でこれを修正しようとしましたが、役に立ちませんでした。

これを期待通りに動作させる方法について、何かアイデアをお持ちの方はいらっしゃいますか? または、Tomcat の起動が成功するまで待つ方法についてのアイデア (TCP ポートが起動したことを認識するまで待つことを考えていますが、今やろうとしていることよりも複雑になると思われます)。一致時に awk で「killall tail」を実行して動作させることはできましたが、その解決策には満足していません。RHEL4 でこれを動作させようとしていることに注意してください。

答え1

このようなもの?

mkfifo child.fifo
tail -f child.out > child.fifo &
pid=$!
grep -q B child.fifo && kill $pid

略さずに:

#!/bin/sh    
rm -f child.out
./child.sh > child.out &
mkfifo child.fifo
tail -f child.out > child.fifo &
pid=$!
grep -q B child.fifo && kill $pid
rm child.fifo

20秒で実行されるようです。

$ time ./test2.sh

real    0m20.156s
user    0m0.033s
sys     0m0.058s

アップデート

この方法も機能するようです:

#!/bin/sh
rm -f child.out
./child.sh > child.out &
(tail -f child.out | grep -q B child.out)

すぐに終了してしまう場合は、スリープ1を追加してみてください。

#!/bin/sh
rm -f child.out
./child.sh > child.out &
sleep 1
(tail -f child.out | grep -q B child.out)

答え2

すべて1行で、「do foo」を「command」に置き換えます。

# サービス tomcat6 開始
# tail -f /var/log/tomcat6/catalina.out | awk '/Server startup/{system("do foo"); exit 0}'

答え3

末尾は削除します。空の child.out から開始するので、末尾は必要ありません。また、(お分かりのように) 末尾は問題を複雑にします。スリープ ループの最初のインスタンスを grep するだけです。

until fgrep -q "Server startup" child.out; do sleep 1; done

常に空の catalina.out から開始するとは限らないため、末尾を保持する必要がある場合は、末尾をループ内に配置します。

until tail child.out| fgrep -q "Server startup"; do sleep 1; done

関連情報