Bagaimana cara 'menangkap' aliran berkelanjutan?

729

Apakah itu mungkin untuk digunakan greppada aliran berkelanjutan?

Yang saya maksud adalah semacam tail -f <file>perintah, tetapi dengan greppada output untuk menjaga hanya garis yang menarik minat saya.

Saya sudah mencoba tail -f <file> | grep patterntetapi tampaknya grephanya bisa dieksekusi setelah tailselesai, artinya tidak pernah.

Matthieu Napoli
sumber
9
Sangat mungkin program yang menghasilkan file tidak membilas outputnya.
Steve-o
tail -f filebekerja (saya melihat output baru dalam waktu nyata)
Matthieu Napoli
6
Akan sesuai untuk unix.stackexchange.com
Luc M
@Luc memang, tidak memikirkan itu
Matthieu Napoli
Mungkin tidak ada baris baru di aliran input Anda? Jika demikian grep tidak akan melanjutkan.
Lynch

Jawaban:

1328

Aktifkan grepmode line buffering saat menggunakan BSD grep (FreeBSD, Mac OS X dll.)

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

Anda tidak perlu melakukan ini untuk GNU grep (digunakan pada hampir semua Linux) karena akan memerah secara default (YMMV untuk Unix-like lain seperti SmartOS, AIX atau QNX).

anak laki-laki
sumber
3
@MichaelNiemand Anda bisa menggunakan file tail -F | grep --line-buffered my_pattern
jcfrei
47
@MichaelGoldshteyn Tenang. Orang memilihnya karena mereka menemukan halaman ini ketika mereka google "grep line buffered" dan itu memecahkan masalah bagi mereka yang mungkin bukan orang yang ditanyakan sebagai pertanyaan.
raine
4
Saya datang ke sini mencoba untuk menangkap keluaran strace. Tanpa --line-buffereditu, itu tidak akan berhasil.
sjas
5
@MichaelGoldshteyn (dan para pendukung komentarnya): Saya selalu mengalami masalah ini tail -f | grep, dan --line-bufferedmenyelesaikannya untuk saya (di Ubuntu 14.04, GNU grep versi 2.16). Di mana logika "use line buffering if stdout is a tty" diterapkan? Di git.savannah.gnu.org/cgit/grep.git/tree/src/grep.c , line_buffereddiset hanya oleh parser argumen.
Aasmund Eldhuset
8
@MichaelGoldshteyn Saya menggunakan macOS menggunakan BSD grep dan tanpa --line-bufferedsaya tidak mendapatkan output. Namun, setelah pengujian, sepertinya GNU grep melakukan apa yang Anda gambarkan. Jadi seperti kebanyakan hal Unix, itu tergantung pada implementasi platform Anda. Karena pertanyaan tidak menentukan platform, informasi Anda tampaknya salah - setelah meninjau kode untuk BSD grep dan membandingkannya dengan GNU grep, perilaku tersebut pasti dikendalikan oleh opsi - line-buffered. Hanya saja grep GNU memerah secara default.
Richard Waite
119

Saya menggunakan tail -f <file> | grep <pattern>semua waktu.

Ini akan menunggu sampai grep memerah, tidak sampai selesai (saya menggunakan Ubuntu).

Irit Katriel
sumber
4
Yang bisa bertahan cukup lama, jadi cobalah untuk tidak sabar.
glglgl
Berapa lama kira-kira?
Matthieu Napoli
@ Matthieu: Tergantung terutama pada apa yang Anda perjuangkan, dan seberapa besar buffer pada OS Anda. Jika grep hanya cocok dengan string pendek setiap beberapa jam, itu akan menjadi beberapa hari sebelum flush pertama.
tripleee
13
Tail tidak menggunakan buffering keluaran - grep tidak.
XzKto
7
Tidak, grep tidak melakukan buffering output ketika output menuju ke perangkat tty, karena jelas ada dalam jawaban ini. Itu penyangga garis! Ini adalah jawaban yang benar dan harus menjadi jawaban yang diterima. Lihat komentar saya yang lebih panjang untuk jawaban yang saat ini diterima ( salah ) untuk detail lebih lanjut.
Michael Goldshteyn
67

Saya pikir masalah Anda adalah bahwa grep menggunakan beberapa buffering output. Mencoba

tail -f file | stdbuf -o0 grep my_pattern

itu akan mengatur mode buffering output grep ke unbuffered.

XzKto
sumber
7
Dan ini memiliki kelebihan yang bisa digunakan untuk banyak perintah lain selain itu grep.
Peter V. Mørch
4
Namun, seperti yang saya temukan setelah bermain lebih banyak dengannya, beberapa perintah hanya menyiram output mereka ketika terhubung ke tty, dan untuk itu, unbuffer(dalam expect-devpaket pada debian) adalah raja . Jadi saya akan menggunakan unbuffer di atas stdbuf.
Peter V. Mørch
5
@ Peter V. Mørch Ya, Anda benar, kadang-kadang unbuffer dapat bekerja di mana stdbuf tidak bisa. Tapi saya pikir Anda sedang mencoba menemukan program 'ajaib' yang akan selalu memperbaiki masalah Anda alih-alih memahami masalah Anda. Membuat tty virtual adalah tugas yang tidak terkait. Stdbuf melakukan apa yang kita inginkan (menetapkan buffer output standar untuk memberikan nilai), sementara unbuffer melakukan banyak hal tersembunyi yang mungkin tidak kita inginkan (bandingkan interaktif topdengan stdbuf dan unbuffer). Dan benar-benar tidak ada solusi 'ajaib': unbuffer kadang-kadang gagal juga, misalnya awk menggunakan implementasi buffer yang berbeda (stdbuf juga akan gagal).
XzKto
2
"Tapi kupikir kamu sedang berusaha menemukan program 'sihir' yang akan selalu memperbaiki masalahmu alih-alih memahami masalahmu." - Saya pikir kamu benar! ;-)
Peter V. Mørch
1
Beberapa info lebih lanjut tentang stdbuf, `unbuffer, dan stdio buffering di pixelbeat.org/programming/stdio_buffering
Tor Klingberg
13

Jika Anda ingin menemukan kecocokan di seluruh file (bukan hanya ekor), dan Anda ingin itu cocok dan menunggu kecocokan baru, ini berfungsi dengan baik:

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

The -c +0flag mengatakan bahwa output harus mulai 0byte ( -c) dari awal ( +) dari file.

Ken Williams
sumber
12

Dalam kebanyakan kasus, Anda bisa tail -f /var/log/some.log |grep foodan itu akan berfungsi dengan baik.

Jika Anda perlu menggunakan banyak greps pada file log yang sedang berjalan dan Anda menemukan bahwa Anda tidak mendapatkan output, Anda mungkin perlu menempelkan --line-bufferedsakelar ke grep tengah Anda , seperti:

tail -f /var/log/some.log | grep --line-buffered foo | grep bar
Dale Anderson
sumber
7

Anda dapat menganggap jawaban ini sebagai peningkatan .. biasanya saya gunakan

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

-F lebih baik jika file diputar (-f tidak akan berfungsi dengan baik jika file diputar)

-A dan -B berguna untuk mendapatkan garis sebelum dan sesudah terjadinya pola .. blok ini akan muncul di antara pemisah garis putus-putus

Tetapi bagi saya, saya lebih suka melakukan yang berikut

tail -F <file> | less

ini sangat berguna jika Anda ingin mencari di dalam log yang dialirkan. Maksud saya kembali dan maju dan melihat secara mendalam

mebada
sumber
4
grep -C 3 <pattern>, ganti -A <N> dan -B <N> jika N sama.
AKS
6

Tidak melihat siapa pun menawarkan kunjungan biasa untuk ini:

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

Saya lebih suka ini, karena Anda dapat menggunakan ctrl + cuntuk berhenti dan menavigasi file kapan saja, dan kemudian tekan saja shift + funtuk kembali ke pencarian streaming langsung.

Hans.Loven.work
sumber
4

sed akan menjadi pilihan yang lebih baik ( editor aliran )

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

dan kemudian jika Anda ingin perintah ekor keluar setelah Anda menemukan string tertentu:

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

Jelas bashism: $ BASHPID akan menjadi id proses dari perintah tail. Perintah sed adalah setelah tail di pipa, jadi id proses sed akan menjadi $ BASHPID + 1.

Christian Herr
sumber
1
Asumsi bahwa proses selanjutnya yang dimulai pada sistem ( $BASHPID+1) akan menjadi milik Anda adalah salah dalam banyak situasi, dan ini tidak melakukan apa pun untuk menyelesaikan masalah buffering yang mungkin merupakan pertanyaan yang ingin ditanyakan OP. Secara khusus, merekomendasikan seddi grepsini sepertinya hanya masalah preferensi (meragukan). (Anda bisa mendapatkan p;qperilaku grep -m 1jika itu yang ingin Anda sampaikan.)
tripleee
Bekerja, perintah sed mencetak setiap baris segera setelah siap, perintah grep dengan --line-bufferedtidak. Saya dengan tulus tidak mengerti angka minus 1.
MUY Belgium
Sampai sekarang ditetapkan bahwa buffering adalah masalah dengan grep . Tidak diperlukan tindakan khusus untuk menangani buffering garis menggunakan sed , itu adalah perilaku default, karenanya saya menekankan aliran kata . Dan benar, tidak ada jaminan $ BASHPID + 1 akan menjadi pid yang tepat untuk diikuti, tetapi karena alokasi pid adalah berurutan dan perintah pipa diberi pid segera berikut, itu sangat mungkin.
Christian Herr
1

Ya, ini sebenarnya akan bekerja dengan baik. Grepdan sebagian besar perintah Unix beroperasi pada stream satu baris pada satu waktu. Setiap baris yang keluar dari ekor akan dianalisis dan diteruskan jika cocok.

Caleb
sumber
2
Itu sebenarnya tidak benar. Jika grepadalah perintah terakhir dalam rantai pipa, itu akan bertindak seperti yang Anda jelaskan. Namun, jika itu di tengah itu akan buffer sekitar 8k output sekaligus.
Mahmoud Al-Qudsi
1

Perintah yang satu ini bekerja untuk saya (Suse):

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

mengumpulkan login ke layanan surat

pengguna10584393
sumber
-1

Anda tentu tidak akan berhasil

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

ketika Anda menggunakan "colortail" sebagai alias untuk ekor, mis. di bash

alias tail='colortail -n 30'

Anda dapat memeriksa berdasarkan jenis alias jika ini menghasilkan sesuatu seperti alias ekor isan colortail -n 30. maka Anda memiliki pelakunya :)

Larutan:

hapus alias dengan

unalias tail

pastikan Anda menggunakan biner ekor 'asli' dengan perintah ini

type tail

yang akan menghasilkan sesuatu seperti:

tail is /usr/bin/tail

dan kemudian Anda dapat menjalankan perintah Anda

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

Semoga berhasil.

pengguna882786
sumber
-4

Gunakan awk (utilitas bash hebat lainnya) alih-alih grep di mana Anda tidak memiliki opsi buffered baris! Ini akan terus mengalirkan data Anda dari ekor.

ini adalah bagaimana kamu menggunakan grep

tail -f <file> | grep pattern

Ini adalah bagaimana Anda akan menggunakan awk

tail -f <file> | awk '/pattern/{print $0}'
Atif
sumber
6
Ini tidak benar; Awk keluar dari kotak melakukan buffering garis, seperti kebanyakan alat Unix standar lainnya. (Terlebih lagi, {print $0}ini mubazir, karena pencetakan adalah tindakan default ketika suatu kondisi lewat.)
tripleee