パターンに一致するまでファイルに対してテール-Fを実行したいと思います。 awkを使用する方法を見つけましたが、私見では私のコマンドは本当にクリーンではありません。問題は、いくつかの制限があるため、私が必要 1行でそれを実行することです。
tail -n +0 -F /tmp/foo | \
awk -W interactive '{if ($1 == "EOF") exit; print} END {system("echo EOF >> /tmp/foo")}'
テールはEOFがファイルに表示されるまでブロックされます。これは非常にうまく機能します。awkの「exit」はすぐには終了しないため、ENDブロックは必須です。awkは前にENDブロックを評価します。終了:ENDブロックは(tailのために)読み取り呼び出しでハングするため、最後に行う必要があるのは、ファイルに別の行を書き込んで、tailを強制的に終了させることです。
誰かがそれを行うためのより良い方法を知っていますか?
これを試して:
sh -c 'tail -n +0 -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
「EOF」文字列が/ tmp/fooに表示されるとすぐに、コマンドライン全体が終了します。
副作用が1つあります。/tmp/fooに何かが書き込まれるまで、テールプロセスは(バックグラウンドで)実行されたままになります。
Tailの--pidオプションを使用すると、Shellが終了するとtailが停止します。テールファイルに余分なものを追加する必要はありません。
sh -c 'tail -n +0 --pid=$$ -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
私は解決策で結果を出していません:
sh -c 'tail -n +0 -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
ファイルに追加された行がこれ以上ない場合、sedは入力を読み取らないため、バッファーに関連するいくつかの問題があります。だから、もう少し研究して、私はこれを思いついた:
sed '/EOF/q' <(tail -n 0 -f /tmp/foo)
スクリプトは https://Gist.github.com/2377029 にあります
これはあなたのために働きますか?
tail -n +0 -F /tmp/foo | sed '/EOF/q'
「EOF」があなたが探しているパターンだと思います。 sed
コマンドは、それが見つかると終了します。つまり、tail
は、次に書き込むときに終了する必要があります。
ファイルの終わり頃にパターンが見つかった場合、tail
がぶらぶらして、ファイルに表示されることのない出力がさらに表示されるのを待つという外部の可能性があると思います。それが本当に懸念される場合は、おそらくそれを殺すように手配することができます-パイプライン全体はsed
が終了すると終了します(それが正しい動作ではないと判断する面白いシェルを使用している場合を除く)。
恐れられているように、bash
(少なくとも、MacOS Xでは、おそらくどこでも)は、tail
が終了しても、sed
が終了するのを待つ必要があると考えるシェルです。 。時々-私が好きなよりも頻繁に-私は古き良きBourneShellの振る舞いを好みますが、それはそれほど賢くなく、したがってBashよりも間違っていると推測されることが少なくなりました。 dribbler
は、メッセージを1秒に1回ドリブルするプログラム(例では「1:Hello」など)で、出力は標準出力になります。 Bashでは、このコマンドシーケンスは、別のウィンドウで「echo pqr >>/tmp/foo
」を実行するまでハングします。
date
{ timeout -t 2m dribbler -t -m Hello; echo EOF; } >/tmp/foo &
echo Hi
sleep 1 # Ensure /tmp/foo is created
tail -n +0 -F /tmp/foo | sed '/EOF/q'
date
残念ながら、この動作を制御するオプションがすぐにはわかりません。 shopt lithist
を見つけましたが、それはこの問題とは関係ありません。
Korn Shellを使用してそのスクリプトを実行すると、期待どおりに機能することに注意してください。tail
が何とか殺されるために潜んでいます。 2番目のdateコマンドが完了した後、そこで機能するのは 'echo pqr >> /tmp/foo
'です。
これはTclが非常に得意なことです。以下が「tail_until.tcl」の場合、
#!/usr/bin/env tclsh
proc main {filename pattern} {
set pipe [open "| tail -n +0 -F $filename"]
set pid [pid $pipe]
fileevent $pipe readable [list handler $pipe $pattern]
vwait ::until_found
catch {exec kill $pid}
}
proc handler {pipe pattern} {
if {[gets $pipe line] == -1} {
if {[eof $pipe]} {
set ::until_found 1
}
} else {
puts $line
if {[string first $pattern $line] != -1} {
set ::until_found 1
}
}
}
main {*}$argv
次に、tail_until.tcl /tmp/foo EOF
これは、grepの代わりにsedを使用して、tailの出力がstdoutに送られるようにするJonのソリューションの拡張バージョンです。
sed -r '/EOF/q' <( exec tail -n +0 -f /tmp/foo ); kill $! 2> /dev/null
これは、sedがtailの前に作成されるため、$!テールのPIDを保持します
Sh -cソリューションに対するこれの主な利点は、shを強制終了すると、「終了」などの出力に歓迎されない何かが出力されるように見えることです。
sh -c 'tail -n +0 --pid=$$ -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
ここでの主な問題は$$
にあります。コマンドをそのまま実行すると、$$
はshではなく、コマンドが実行されている現在のシェルのPIDに設定されます。
キルを機能させるには、kill $$
をkill \$$
に変更する必要があります
その後、tailコマンドに渡された--pid=$$
を安全に取り除くことができます。
要約すると、以下は問題なく機能します。
/bin/sh -c 'tail -n 0 -f /tmp/foo | { sed "/EOF/ q" && kill \$$ ;}
オプションで、-n
をsed
に渡して、静かに保つことができます:)
ぶら下がっているtail
プロセスも強制終了するには、(Bash)プロセス置換コンテキストでtail
コマンドを実行します。これは、バックグラウンドプロセスであるかのように後で強制終了できます。 ( から取得したコード 'tail -f'からパイプラインを介して1行を読み取り、終了する方法は? )。
: > /tmp/foo
grep -m 1 EOF <( exec tail -f /tmp/foo ); kill $! 2> /dev/null
echo EOF > /tmp/foo # terminal window 2
別の方法として、名前付きパイプを使用することもできます。
(
: > /tmp/foo
rm -f pidfifo
mkfifo pidfifo
sh -c '(tail -n +0 -f /tmp/foo & echo $! > pidfifo) |
{ sed "/EOF/ q" && kill $(cat pidfifo) && kill $$ ;}'
)
echo EOF > /tmp/foo # terminal window 2
tomcatで使用する準備ができました=
sh -c'tail -f --pid = $$ catalina.out | {grep -i -m 1 "Server startup in" && kill $$;} '
上記のシナリオの場合:
sh -c 'tail -f --pid=$$ /tmp/foo | { grep -i -m 1 EOF && kill $$ ;}'