Wykonaj tail - f aż do dopasowania wzoru

Chcę wykonać tail-F na pliku, dopóki nie dopasuje wzorca. Znalazłem sposób za pomocą awk, ale IMHO moje polecenie nie jest naprawdę czyste. Problem polega na tym, że muszę to zrobić tylko w jednej linii, z powodu pewnych ograniczeń.

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

Ogon zostanie zablokowany, dopóki w pliku nie pojawi się EOF. Działa całkiem nieźle. Blok końcowy jest obowiązkowy, ponieważ "wyjście" awk nie kończy się od razu. To sprawia, że awk do ewaluacji bloku końcowego przed zakończeniem. Blok końcowy wisi na wywołaniu read (z powodu ogona), więc ostatnią rzeczą, jaką muszę zrobić, to napisać kolejną linię w pliku, aby zmusić tail do wyjścia.

Czy ktoś zna lepszy sposób na to?
Author: Sam Alba, 2011-02-17

10 answers

Spróbuj tego:

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

Cała linia poleceń zakończy się, gdy tylko w /tmp/foo pojawi się ciąg "EOF".

Jest jeden efekt uboczny: proces ogonowy pozostanie uruchomiony (w tle), dopóki cokolwiek nie zostanie zapisane do /tmp/foo.

 26
Author: jpetazzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-17 19:56:46

Użyj opcji --pid taila, a tail zatrzyma się, gdy powłoka umrze. Nie ma potrzeby dodawania dodatkowych do pliku.

sh -c 'tail -n +0 --pid=$$ -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
 29
Author: Greg Barrett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-24 23:53:05

Nie znalazłem rozwiązania:

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

Jest pewien problem związany z buforem, ponieważ jeśli nie ma więcej linii dołączonych do pliku, to sed nie odczyta danych wejściowych. Tak, z trochę więcej badań wymyśliłem to:

sed '/EOF/q' <(tail -n 0 -f /tmp/foo)

Skrypt jest w https://gist.github.com/2377029

 8
Author: harley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-13 13:57:15

Czy to działa dla Ciebie?

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

Zakładam, że' EOF ' to wzór, którego szukasz. Polecenie sed kończy działanie, gdy je znajdzie, co oznacza, że {[3] } powinno zakończyć się przy następnym zapisie.

Przypuszczam, że istnieje zewnętrzna szansa, że tail będzie się kręcić, jeśli wzorzec zostanie znaleziony na końcu pliku, czekając, aż w pliku pojawi się więcej danych wyjściowych, które nigdy się nie pojawią. Jeśli to naprawdę niepokojące, możesz zaaranżować zabicie go. - rurociąg jako całość zakończy się, gdy sed zakończy się (chyba że używasz śmiesznej powłoki, która zdecyduje, że nie jest to właściwe zachowanie).


Zrzęda o Bash

Jak się obawiano, bash (przynajmniej na MacOS X, ale prawdopodobnie wszędzie) jest powłoką, która uważa, że musi czekać na tail, aby zakończyć, nawet jeśli sed zamknąć. Czasami - częściej niż mi się podoba-wolę zachowanie starej, dobrej powłoki Bourne ' a, która nie była tak mądra i dlatego się pomyliła rzadziej niż Bash. {[9] } jest programem, który wysyła komunikaty na sekundę ('1: Hello' itd. W przykładzie), A wyjście na standardowe wyjście. W Bash ta sekwencja poleceń zawiesza się, dopóki nie wykonałem 'echo pqr >>/tmp/foo' w osobnym oknie.

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

Niestety, nie od razu widzę opcję kontrolowania tego zachowania. Znalazłem shopt lithist, ale to nie ma związku z tym problemem.

Hurra dla Korn Shell

Zauważam, że kiedy uruchamiam ten skrypt używając powłoki Korn, to działa tak , jak bym się spodziewał-zostawiając tail czającego się wokół, by zostać zabitym. To, co tam działa, to "echo pqr >> /tmp/foo " po zakończeniu drugiego polecenia date.

 4
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-17 03:25:49

To jest coś, w czym Tcl jest całkiem dobry. Jeśli poniżej znajduje się "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

Then you ' d do tail_until.tcl /tmp/foo EOF

 4
Author: glenn jackman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-17 14:21:07

Oto rozszerzona wersja rozwiązania Jona, która używa sed zamiast grep tak, że wyjście tail przechodzi na stdout:

sed -r '/EOF/q' <( exec tail -n +0 -f /tmp/foo ); kill $! 2> /dev/null

To działa, ponieważ sed powstaje przed tail so $! trzyma PID ogona

Główną zaletą tego rozwiązania w stosunku do sh-c jest to, że zabicie SH wydaje się drukować coś na wyjściu, takie jak "Zakończone", które jest niemile widziane

 2
Author: DanyalBurke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-28 18:50:24
sh -c 'tail -n +0 --pid=$$ -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'

Tutaj głównym problemem jest $$. Jeśli uruchomisz polecenie tak, jak jest, $$ jest ustawione nie na sh, ale na PID bieżącej powłoki, w której uruchamiane jest polecenie.

Aby kill działał musisz zmienić kill $$ na kill \$$

Po tym możesz bezpiecznie pozbyć się --pid=$$ przekazanego do tail command.

Podsumowując, następujące będzie działać dobrze:

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

Opcjonalnie możesz przejść -n do sed, aby zachować spokój:)

 2
Author: Max Horlanchuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-02 16:41:54

Aby zabić zwisający proces tail, możesz wykonać polecenie tail w kontekście podstawienia (Bash) procesu, które później można zabić tak, jakby był to proces Ukryty. (Kod zaczerpnięty z Jak odczytać jedną linię z 'tail-f' przez rurociąg, a następnie zakończyć?).

: > /tmp/foo
grep -m 1 EOF <( exec tail -f /tmp/foo ); kill $! 2> /dev/null
echo EOF > /tmp/foo  # terminal window 2

Jako alternatywę możesz użyć nazwanej rury.

(
: > /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
 1
Author: jon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-20 10:18:24

Gotowy do użycia dla tomcat =

Sh-c 'tail-f --pid=$ $ catalina.out | {grep-i-m 1 "uruchamianie serwera w" & & kill $$;} '

Dla powyższego scenariusza:

sh -c 'tail -f   --pid=$$ /tmp/foo | { grep -i -m 1 EOF && kill $$ ;}'
 1
Author: mayank arora,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-14 08:52:08
tail -f <filename> | grep -q "<pattern>"
 -2
Author: techmonk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-16 10:51:40