26

tail -Fパターンに一致するまでファイルに対して実行したい。を使用する方法を見つけましたawkが、私見では私のコマンドは本当にきれいではありません。問題は、いくつかの制限があるため、1行で実行する必要があることです。

tail -n +0 -F /tmp/foo | \
awk -W interactive '{if ($1 == "EOF") exit; print} END {system("echo EOF >> /tmp/foo")}'

テールはファイルに表示されるまでブロックEOFされます。それはかなりうまくいきます。awkexitはすぐには終了しないため、ENDブロックは必須です。終了する前awkevalENDブロックになります。ENDブロックは(tailのために)読み取り呼び出しでハングするため、最後に行う必要があるのは、ファイルに別の行を書き込んで、tailを強制的に終了させることです。

誰かがそれを行うためのより良い方法を知っていますか?

4

10 に答える 10

42

テールの--pidオプションを使用すると、シェルが死ぬとテールが停止します。テールファイルに余分なものを追加する必要はありません。

sh -c 'tail -n +0 --pid=$$ -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
于 2011-02-24T23:53:05.597 に答える
35

これを試して:

sh -c 'tail -n +0 -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'

「EOF」文字列がに表示されるとすぐに、コマンドライン全体が終了し/tmp/fooます。

副作用が1つあります。tail何かが書き込まれるまで、プロセスは(バックグラウンドで)実行されたままになり/tmp/fooます。

于 2011-02-17T19:45:15.437 に答える
9

私は解決策で結果を出していません:

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にあります

于 2012-04-13T13:57:15.017 に答える
5

これは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

于 2011-02-17T14:21:07.603 に答える
4

これはあなたのために働きますか?

tail -n +0 -F /tmp/foo | sed '/EOF/q'

'EOF'があなたが探しているパターンだと思います。sedコマンドは、見つかったときに終了します。つまり、次に書き込むときに終了する必要tailがあります。

tailファイルの終わり頃にパターンが見つかった場合、ファイルに表示されることのない出力がさらに表示されるのを待つという外部の可能性があると思います。それが本当に懸念される場合は、おそらくそれを殺すように手配することができます-パイプライン全体は終了時にsed終了します(それが正しい動作ではないと判断する面白いシェルを使用している場合を除く)。


Bashについて不平を言う

恐れられているように、bash(少なくともMacOS Xでは、おそらくどこでも)tail終了するのを待ってぶらぶらする必要があると考えるシェルですsed。時々-私が好きなよりも頻繁に-私は古き良きBourneシェルの振る舞いを好みますが、それはそれほど賢くなく、したがって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ましたが、それはこの問題とは無関係です。

KornShellのHooray

Kornシェルを使用してそのスクリプトを実行すると、期待どおりに機能することに注意してくださいtail。何とかして殺されるために潜んでいます。echo pqr >> /tmp/foo2番目のdateコマンドが完了した後、そこで機能するのは' 'です。

于 2011-02-17T02:47:00.733 に答える
3

これは、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を強制終了すると、「終了」などの出力に歓迎されない何かが出力されるように見えることです。

于 2011-10-28T18:50:24.037 に答える
2
sh -c 'tail -n +0 --pid=$$ -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'

ここでの主な問題は$$です。コマンドをそのまま実行する場合は、$$shではなく、コマンドが実行されている現在のシェルのPIDに設定されます。

kill $$キルを機能させるには、次のように変更する必要がありますkill \$$

--pid=$$その後、 tailコマンドに渡されたものを安全に取り除くことができます。

要約すると、以下は問題なく機能します。

/bin/sh -c 'tail -n 0 -f /tmp/foo | { sed "/EOF/ q" && kill \$$ ;}

オプションで、に渡して静かに保つことができ-nますsed:)

于 2011-05-06T02:02:07.527 に答える
1

ぶら下がっている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
于 2011-09-18T17:09:06.587 に答える
1

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 $$ ;}'
于 2018-02-14T08:52:08.713 に答える
-3
tail -f <filename> | grep -q "<pattern>"
于 2015-10-16T10:51:40.007 に答える