Jak „grep” ciągły strumień?

729

Czy można tego używać grepw ciągłym strumieniu?

Mam na myśli rodzaj tail -f <file>polecenia, ale z grepwyjściem, aby zachować tylko te linie, które mnie interesują.

Próbowałem, tail -f <file> | grep patternale wydaje się, że grepmożna go wykonać tylko po tailzakończeniu, czyli nigdy.

Matthieu Napoli
źródło
9
Jest wysoce prawdopodobne, że program generujący plik nie opróżnia danych wyjściowych.
Steve-o
tail -f filedziała (widzę nową produkcję w czasie rzeczywistym)
Matthieu Napoli
6
Byłoby właściwe dla unix.stackexchange.com
Luc M
@Luc, naprawdę, nie pomyślałem o tym
Matthieu Napoli
Może w Twoim strumieniu wejściowym nie ma żadnych nowych wierszy? Jeśli tak, grep nie będzie kontynuował.
Lynch,

Odpowiedzi:

1326

Włącz greptryb buforowania linii podczas korzystania z BSD grep (FreeBSD, Mac OS X itp.)

tail -f file | grep --line-buffered my_pattern

Nie musisz tego robić w przypadku GNU grep (używanego prawie na każdym Linuksie), ponieważ domyślnie będzie się opróżniał (YMMV dla innych systemów uniksowych, takich jak SmartOS, AIX lub QNX).

berbeć
źródło
3
@MichaelNiemand możesz użyć pliku tail -F | grep --line-buffered my_pattern
jcfrei
47
@MichaelGoldshteyn Spokojnie. Ludzie głosują za tym, ponieważ znajdują tę stronę, kiedy wyszukują w Google „buforowaną linię grep” i rozwiązuje to dla nich problem, który może nie być tym, który postawiono jako pytanie.
raine
4
Przybyłem tutaj, próbując przywrócić wydajność strace. Bez tego --line-bufferednie będzie działać.
sjas
5
@MichaelGoldshteyn (i twórcy jego komentarza): Zawsze miałem ten problem tail -f | grepi --line-bufferedrozwiązałem go dla mnie (w Ubuntu 14.04, GNU grep wersja 2.16). Gdzie jest zaimplementowana logika „użyj buforowania linii, jeśli standardowe wyjście jest tty”? W git.savannah.gnu.org/cgit/grep.git/tree/src/grep.c , line_bufferedjest ustawiony tylko przez parser argumentów.
Aasmund Eldhuset
8
@MichaelGoldshteyn Korzystam z macOS przy użyciu BSD grep i bez niego --line-bufferednie otrzymuję danych wyjściowych. Jednak po przetestowaniu wygląda na to, że GNU grep robi to, co opisujesz. Tak jak większość rzeczy w Uniksie, zależy to od implementacji twojej platformy. Ponieważ pytanie nie określało platformy, twoje informacje wydają się fałszywe - po przejrzeniu kodu BSD grep i porównaniu go z GNU grep, zachowanie jest zdecydowanie kontrolowane przez opcję --line-buforowaną. Tyle, że tylko GNU grep domyślnie się opróżnia.
Richard Waite
118

Używam tail -f <file> | grep <pattern>cały czas.

Poczeka, aż grep się opróżni, a nie do końca (używam Ubuntu).

Irit Katriel
źródło
4
Co może trwać dość długo, więc staraj się nie zniecierpliwić.
glglgl
Jak długo może to potrwać?
Matthieu Napoli
@Matthieu: Zależy głównie od tego, za co grep, i jak duże są bufory w twoim systemie operacyjnym. Jeśli grep pasuje tylko do krótkiego ciągu co kilka godzin, minie kilka dni przed pierwszym spłukaniem.
tripleee
13
Ogon nie korzysta z buforowania wyjściowego - grep tak.
XzKto,
7
Nie, grep nie buforuje danych wyjściowych, gdy dane wyjściowe trafiają do urządzenia tty, jak wyraźnie widać w tej odpowiedzi. Działa buforowanie linii! To jest poprawna odpowiedź i powinna być odpowiedzią zaakceptowaną. Zobacz mój dłuższy komentarz do obecnie przyjętej ( złej ) odpowiedzi, aby uzyskać więcej informacji.
Michael Goldshteyn,
67

Myślę, że twoim problemem jest to, że grep używa buforowania danych wyjściowych. Próbować

tail -f file | stdbuf -o0 grep my_pattern

ustawia tryb buforowania wyjścia grep na niebuforowany.

XzKto
źródło
7
Ma to tę zaletę, że może być używane do wielu innych poleceń poza tym grep.
Peter V. Mørch,
4
Jednak, jak odkryłem po większej ilości zabawy, niektóre polecenia opróżniają swoje wyjście dopiero po podłączeniu do tty, a do tego unbuffer(w expect-devpakiecie na debianie) jest królem . Więc użyłbym unbuffer zamiast stdbuf.
Peter V. Mørch,
5
@Peter V. Mørch Tak, masz rację, buforowanie może czasem działać tam, gdzie nie działa stdbuf. Ale myślę, że próbujesz znaleźć program „magiczny”, który zawsze rozwiąże twoje problemy, zamiast je rozumieć. Utworzenie wirtualnego tty jest niepowiązanym zadaniem. Stdbuf robi dokładnie to, co chcemy (ustawia standardowy bufor wyjściowy, aby dać wartość), podczas gdy unbuffer robi wiele ukrytych rzeczy, których możemy nie chcieć (porównaj interaktywnie topz stdbuf i unbuffer). I tak naprawdę nie ma „magicznego” rozwiązania: czasami buforowanie również zawiedzie, na przykład awk używa innej implementacji bufora (stdbuf też zawiedzie).
XzKto
2
„Ale myślę, że próbujesz znaleźć program„ magiczny ”, który zawsze rozwiąże twoje problemy, zamiast je rozumieć.” - Myślę, że masz rację! ;-)
Peter V. Mørch,
1
Więcej informacji na temat stdbuf, `unbuffer i buforowanie stdio na pixelbeat.org/programming/stdio_buffering
Tor Klingberg
13

Jeśli chcesz znaleźć dopasowania w całym pliku (nie tylko ogon) i chcesz, aby siedział i czekał na nowe dopasowania, działa to dobrze:

tail -c +0 -f <file> | grep --line-buffered <pattern>

-c +0Flaga mówi, że wyjście powinno rozpocząć 0bajtów ( -c) od początku ( +) z pliku.

Ken Williams
źródło
12

W większości przypadków możesz tail -f /var/log/some.log |grep fooi będzie działać dobrze.

Jeśli potrzebujesz użyć wielu grepów w działającym pliku dziennika i okaże się, że nie otrzymujesz danych wyjściowych, może być konieczne włożenie --line-bufferedprzełącznika do środkowego grepa (s), tak jak poniżej:

tail -f /var/log/some.log | grep --line-buffered foo | grep bar
Dale Anderson
źródło
7

możesz uznać tę odpowiedź za udoskonalenie .. zwykle używam

tail -F <fileName> | grep --line-buffered  <pattern> -A 3 -B 5

-F jest lepszy w przypadku obracania pliku (-f nie będzie działał poprawnie, jeśli plik został obrócony)

-A i -B są przydatne do pobierania linii tuż przed i po wystąpieniu wzoru. Bloki te pojawią się między separatorami linii przerywanej

Ale dla mnie wolę robić następujące rzeczy

tail -F <file> | less

jest to bardzo przydatne, jeśli chcesz przeszukiwać dzienniki przesyłane strumieniowo. Mam na myśli cofanie się i naprzód i głębokie spojrzenie

mebada
źródło
4
grep -C 3 <pattern>, zastępuje -A <N> i -B <N>, jeśli N jest takie samo.
AKS
6

Nie widziałem nikogo, kto zaoferowałby mi to za to:

less +F <file>
ctrl + c
/<search term>
<enter>
shift + f

Wolę to, ponieważ możesz użyć ctrl + cdo zatrzymania pliku i poruszania się po nim, a następnie po prostu naciśnij, shift + faby powrócić do wyszukiwania strumieniowego na żywo.

Hans.Loven.work
źródło
4

sed byłby lepszym wyborem ( edytor strumieniowy )

tail -n0 -f <file> | sed -n '/search string/p'

a jeśli chcesz, aby polecenie tail zakończyło działanie po znalezieniu określonego ciągu:

tail --pid=$(($BASHPID+1)) -n0 -f <file> | sed -n '/search string/{p; q}'

Oczywiście bashism: $ BASHPID będzie identyfikatorem procesu polecenia tail. Komenda sed jest następna po ogonie w rurze, więc identyfikator procesu sed to $ BASHPID + 1.

Christian Herr
źródło
1
Założenie, że następny proces uruchomiony w systemie ( $BASHPID+1) będzie twój, jest fałszywe w wielu sytuacjach i nie rozwiązuje to problemu buforowania, o który prawdopodobnie chciał zapytać OP. W szczególności zaleca sedsię greptutaj wydaje się jedynie kwestią (wątpliwej) preferencji. (Możesz uzyskać p;qzachowanie, grep -m 1jeśli to jest punkt, który próbujesz osiągnąć.)
tripleee
Działa, polecenie sed wypisuje każdą linię, gdy tylko będzie gotowe, polecenie grep --line-bufferednie. Szczerze nie rozumiem minus 1.
MUY Belgia,
Dotychczas ustalono, że buforowanie stanowi problem z grep . Żadne specjalne działanie nie jest wymagane do obsługi buforowania linii za pomocą sed , jest to zachowanie domyślne, stąd mój nacisk na strumień słów . I prawda, nie ma gwarancji, że $ BASHPID + 1 będzie poprawnym pid do naśladowania, ale ponieważ alokacja pid jest sekwencyjna, a do polecenia potokowego przypisany jest pid bezpośrednio po nim, jest całkowicie prawdopodobne.
Christian Herr
1

Tak, to naprawdę będzie działać dobrze. Grepi większość poleceń Uniksa działa na strumieniach jedna linia na raz. Każda linia wychodząca z ogona zostanie przeanalizowana i przekazana, jeśli pasuje.

Caleb
źródło
2
To nie jest poprawne. Jeśli grepjest to ostatnie polecenie w łańcuchu potoków, będzie działać zgodnie z objaśnieniem. Jednak jeśli jest w środku, buforuje około 8k danych naraz.
Mahmoud Al-Qudsi
1

To jedno polecenie działa dla mnie (Suse):

mail-srv:/var/log # tail -f /var/log/mail.info |grep --line-buffered LOGIN  >> logins_to_mail

zbieranie danych logowania do usługi pocztowej

użytkownik10584393
źródło
-1

z pewnością nie odniesiesz sukcesu

tail -f /var/log/foo.log |grep --line-buffered string2search

kiedy używasz „colortail” jako aliasu dla ogona, np. w bash

alias tail='colortail -n 30'

możesz sprawdzić według typu aliasu, czy wyświetla to coś w rodzaju aliasu ogona colortail -n 30. to masz winowajcę :)

Rozwiązanie:

usuń alias za pomocą

unalias tail

upewnij się, że używasz „prawdziwego” pliku binarnego ogona za pomocą tego polecenia

type tail

co powinno wypisać coś takiego:

tail is /usr/bin/tail

a następnie możesz uruchomić polecenie

tail -f foo.log |grep --line-buffered something

Powodzenia.

użytkownik882786
źródło
-4

Użyj awk (kolejne świetne narzędzie do bash) zamiast grep, gdzie nie masz opcji buforowanej linii! Będzie stale przesyłać dane z ogona.

tak używasz grep

tail -f <file> | grep pattern

Tak użyłbyś awk

tail -f <file> | awk '/pattern/{print $0}'
Atif
źródło
6
To nie jest poprawne; Awk po wyjęciu z pudełka wykonuje buforowanie linii, podobnie jak większość innych standardowych narzędzi uniksowych. (Ponadto {print $0}jest zbędny, ponieważ drukowanie jest domyślną czynnością, gdy warunek mija.)
tripleee