Làm thế nào để 'grep' một luồng liên tục?


729

Có thể sử dụng greptrên một luồng liên tục?

Ý tôi là một loại tail -f <file>lệnh, nhưng với grepđầu ra để chỉ giữ các dòng mà tôi quan tâm.

Tôi đã thử tail -f <file> | grep patternnhưng dường như grepchỉ có thể được thực hiện khi tailkết thúc, nghĩa là không bao giờ.


9
Rất có khả năng chương trình tạo tập tin không tuôn ra đầu ra của nó.
Steve-o

tail -f filehoạt động (Tôi thấy đầu ra mới trong thời gian thực)
Matthieu Napoli

6
Sẽ phù hợp với unix.stackexchange.com
Luc M

@Luc thực sự, đã không nghĩ về điều đó
Matthieu Napoli

Có thể không có dòng mới trong luồng đầu vào của bạn? Nếu vậy grep sẽ không tiến hành.
Lynch

Câu trả lời:


1327

Bật grepchế độ đệm dòng khi sử dụng BSD grep (FreeBSD, Mac OS X, v.v.)

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

Bạn không cần phải làm điều này cho GNU grep (được sử dụng trên hầu hết mọi Linux) vì nó sẽ xóa theo mặc định (YMMV cho các lượt thích Unix khác như SmartOS, AIX hoặc QNX).


3
@MichaelNiemand bạn có thể sử dụng tệp đuôi -F | grep
line

47
@MichaelGoldshteyn Hãy dễ dàng. Mọi người ủng hộ nó bởi vì họ tìm thấy trang này khi họ google "grep line đệm" và nó giải quyết một vấn đề cho họ mà có thể không chính xác là câu hỏi được đặt ra.
mưa

4
Tôi đến đây để cố gắng grep đầu ra của strace. Không có --line-buffered, nó sẽ không hoạt động.
sjas

5
@MichaelGoldshteyn (và những người ủng hộ nhận xét của anh ấy): Tôi luôn gặp vấn đề này tail -f | grep--line-bufferedgiải quyết nó cho tôi (trên Ubuntu 14.04, GNU grep phiên bản 2.16). Trường hợp "sử dụng bộ đệm dòng nếu stdout là một tty" được triển khai ở đâu? Trong git.savannah.gnu.org/cgit/grep.git/tree/src/grep.c , chỉ line_bufferedđược đặt bởi trình phân tích cú pháp đối số.
Aasmund Eldhuset

8
@MichaelGoldshteyn Tôi đang sử dụng macOS bằng BSD và không --line-bufferedcó kết quả. Tuy nhiên, sau khi thử nghiệm, có vẻ như GNU grep thực hiện những gì bạn mô tả. Vì vậy, giống như hầu hết mọi thứ Unix, nó phụ thuộc vào việc triển khai nền tảng của bạn. Vì câu hỏi không chỉ định nền tảng, thông tin của bạn có vẻ sai - sau khi xem lại mã cho BSD grep và so sánh nó với GNU grep, hành vi chắc chắn được kiểm soát bởi tùy chọn - được đệm. Theo mặc định, chỉ có GNU grep tuôn ra.
Richard Waite

119

Tôi sử dụng tail -f <file> | grep <pattern>tất cả các thời gian.

Nó sẽ đợi cho đến khi grep tuôn ra, cho đến khi nó kết thúc (Tôi đang sử dụng Ubuntu).


4
Mà có thể kéo dài khá lâu, vì vậy hãy cố gắng đừng nôn nóng.
glglgl

Mất bao lâu?
Matthieu Napoli

@Matthieu: Phụ thuộc chủ yếu vào những gì bạn grep cho và mức độ lớn của bộ đệm trên hệ điều hành của bạn. Nếu grep chỉ khớp với một chuỗi ngắn cứ sau vài giờ, đó sẽ là vài ngày trước lần xả đầu tiên.
tripleee

13
Tail không sử dụng bộ đệm đầu ra - grep nào.
XzKto

7
Không, grep không thực hiện đệm đầu ra khi đầu ra đi đến một thiết bị tty, vì rõ ràng nó nằm trong câu trả lời này. Nó không đệm dòng! Đây là câu trả lời đúng và nên là câu trả lời được chấp nhận. Xem bình luận dài hơn của tôi để trả lời ( sai ) hiện đang được chấp nhận để biết thêm chi tiết.
Michael Goldshteyn

67

Tôi nghĩ rằng vấn đề của bạn là grep sử dụng một số bộ đệm đầu ra. Thử

tail -f file | stdbuf -o0 grep my_pattern

nó sẽ đặt chế độ đệm đầu ra của grep thành không có bộ đệm.


7
Và điều này có lợi thế là nó có thể được sử dụng cho nhiều lệnh khác bên cạnh đó grep.
Peter V. Mørch

4
Tuy nhiên, như tôi đã phát hiện ra sau khi chơi nhiều hơn với nó, một số lệnh chỉ tuôn ra đầu ra của chúng khi được kết nối với một tty, và vì thế, unbuffer(trong expect-devgói trên debian) là vua . Vì vậy, tôi sẽ sử dụng unbuffer trên stdbuf.
Peter V. Mørch

5
@Peter V. Mørch Vâng, bạn đã đúng, unbuffer đôi khi có thể hoạt động ở nơi stdbuf không thể. Nhưng tôi nghĩ rằng bạn đang cố gắng tìm một chương trình 'ma thuật' sẽ luôn khắc phục vấn đề của bạn thay vì hiểu vấn đề của bạn. Tạo một tty ảo là nhiệm vụ không liên quan. Stdbuf thực hiện chính xác những gì chúng ta muốn (đặt bộ đệm đầu ra tiêu chuẩn để đưa ra giá trị), trong khi unbuffer thực hiện rất nhiều thứ ẩn mà chúng ta có thể không muốn (so sánh tương tác topvới stdbuf và unbuffer). Và thực sự không có giải pháp 'ma thuật': đôi khi unbuffer cũng thất bại, ví dụ awk sử dụng bộ đệm khác nhau (stdbuf cũng sẽ thất bại).
XzKto

2
"Nhưng tôi nghĩ rằng bạn đang cố gắng tìm một chương trình 'ma thuật' sẽ luôn khắc phục vấn đề của bạn thay vì hiểu vấn đề của bạn." - Tôi nghĩ bạn đúng! ;-)
Peter V. Mørch

1
Một số thông tin khác về stdbuf, 'unbuffer và stdio đệm tại pixelbeat.org/programming/stdio_buffering
Tor Klingberg

13

Nếu bạn muốn tìm trận đấu trong toàn bộ tệp (không chỉ đuôi) và bạn muốn nó ngồi chờ bất kỳ trận đấu mới nào, điều này sẽ hoạt động tốt:

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

Các -c +0lá cờ nói rằng đầu ra nên bắt đầu 0byte ( -c) từ đầu ( +) của tập tin.


12

Trong hầu hết các trường hợp, bạn có thể tail -f /var/log/some.log |grep foovà nó sẽ hoạt động tốt.

Nếu bạn cần sử dụng nhiều greps trên một tệp nhật ký đang chạy và bạn thấy rằng bạn không nhận được đầu ra, bạn có thể cần phải gắn công --line-bufferedtắc vào grep giữa của mình, như vậy:

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

7

bạn có thể coi câu trả lời này là sự nâng cao .. thông thường tôi đang sử dụng

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

-F tốt hơn trong trường hợp xoay tệp (-f sẽ không hoạt động đúng nếu xoay tệp)

-A và -B rất hữu ích để có được các dòng ngay trước và sau khi xuất hiện mẫu .. các khối này sẽ xuất hiện giữa các dấu phân cách dòng đứt nét

Nhưng đối với tôi, tôi thích làm như sau

tail -F <file> | less

Điều này rất hữu ích nếu bạn muốn tìm kiếm bên trong các bản ghi được truyền phát. Tôi có nghĩa là quay trở lại và nhìn sâu và nhìn sâu


4
grep -C 3 <pattern>, thay thế -A <N> và -B <N> nếu N giống nhau.
AKS

6

Không thấy ai đưa ra cách làm thông thường của tôi cho việc này:

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

Tôi thích điều này, bởi vì bạn có thể sử dụng ctrl + cđể dừng và điều hướng qua tệp bất cứ khi nào, và sau đó chỉ cần nhấn shift + fđể quay lại tìm kiếm trực tuyến, phát trực tuyến.


4

sed sẽ là một lựa chọn tốt hơn ( biên tập luồng )

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

và sau đó nếu bạn muốn lệnh tail thoát ra khi bạn tìm thấy một chuỗi cụ thể:

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

Rõ ràng là một bashism: $ BASHPID sẽ là id quá trình của lệnh tail. Lệnh sed tiếp theo sau đuôi trong đường ống, vì vậy id process process sẽ là $ BASHPID + 1.


1
Giả định rằng quy trình tiếp theo bắt đầu trên hệ thống ( $BASHPID+1) sẽ là của bạn trong nhiều tình huống và điều này không có gì để giải quyết vấn đề đệm có lẽ là điều mà OP đang cố gắng hỏi. Đặc biệt, giới thiệu sedtrên grepđây có vẻ như chỉ là một vấn đề (không rõ ràng) sở thích. (Bạn có thể có p;qhành vi grep -m 1nếu đó là điểm bạn đang cố gắng phân phối.)
tripleee

Hoạt động, lệnh sed in từng dòng ngay khi sẵn sàng, lệnh grep với --line-bufferedkhông. Tôi thực sự không hiểu được điểm trừ 1.
MUY Bỉ

Đây là điều được xác định rằng bộ đệm là vấn đề với grep . Không có hành động đặc biệt nào được yêu cầu để xử lý bộ đệm dòng bằng sed , đó là hành vi mặc định, do đó tôi nhấn mạnh luồng từ . Và đúng, không có gì đảm bảo $ BASHPID + 1 sẽ là pid chính xác để tuân theo, nhưng vì phân bổ pid là tuần tự và lệnh piped được gán một pid ngay sau đó, nên hoàn toàn có thể xảy ra.
Christian Herr

1

Vâng, điều này thực sự sẽ làm việc tốt. Grepvà hầu hết các lệnh Unix hoạt động trên các luồng một dòng tại một thời điểm. Mỗi dòng ra khỏi đuôi sẽ được phân tích và chuyển qua nếu nó phù hợp.


2
Điều đó không thực sự chính xác. Nếu greplà lệnh cuối cùng trong chuỗi ống, nó sẽ hoạt động như bạn giải thích. Tuy nhiên, nếu ở giữa, nó sẽ đệm khoảng 8k đầu ra một lúc.
Mahmoud Al-Qudsi

1

Lệnh này hoạt động với tôi (Suse):

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

thu thập thông tin đăng nhập vào dịch vụ thư


-1

bạn chắc chắn sẽ không thành công với

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

khi bạn sử dụng "colortail" làm bí danh cho đuôi, vd. trong bash

alias tail='colortail -n 30'

bạn có thể kiểm tra theo bí danh nếu điều này xuất ra cái gì đó như bí danh đuôi là colortail -n 30. sau đó bạn có thủ phạm của bạn :)

Giải pháp:

xóa bí danh với

unalias tail

đảm bảo rằng bạn đang sử dụng nhị phân đuôi 'thực' bằng lệnh này

type tail

cái nào sẽ xuất ra cái gì đó như:

tail is /usr/bin/tail

và sau đó bạn có thể chạy lệnh của bạn

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

Chúc may mắn.


-4

Sử dụng awk (một tiện ích bash tuyệt vời khác) thay vì grep nơi bạn không có tùy chọn đệm dòng! Nó sẽ liên tục truyền dữ liệu của bạn từ đuôi.

đây là cách bạn sử dụng grep

tail -f <file> | grep pattern

Đây là cách bạn sẽ sử dụng awk

tail -f <file> | awk '/pattern/{print $0}'

6
Điều này LAF không đúng; Awk out of the box thực hiện bộ đệm dòng, giống như hầu hết các công cụ Unix tiêu chuẩn khác. (Hơn nữa, điều {print $0}này là không cần thiết, vì in là hành động mặc định khi một điều kiện qua.)
tripleee
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.