Tại sao 'grep -q' tiêu thụ toàn bộ tệp đầu vào?


23

Hãy xem xét các tập tin đầu vào sau đây:

1
2
3
4

Đang chạy

{ grep -q 2; cat; } < infile

không in bất cứ điều gì. Tôi hy vọng nó sẽ được in

3
4

Tôi có thể nhận được đầu ra dự kiến ​​nếu tôi thay đổi nó thành

{ sed -n 2q; cat; } < infile

Tại sao lệnh đầu tiên không in đầu ra dự kiến?
Đây là một tệp đầu vào có thể tìm kiếm và theo tiêu chuẩn trong TÙY CHỌN :

-q
      Quiet. Nothing shall be written to the standard output, regardless of 
      matching lines. Exit with zero status if an input line is selected.

và xa hơn nữa, dưới mục SỬ DỤNG ỨNG DỤNG (nhấn mạnh của tôi):

Các -qtùy chọn cung cấp một phương tiện để dễ dàng xác định có hay không một mô hình (hoặc chuỗi) tồn tại trong một nhóm các tập tin. Khi tìm kiếm một số tệp, nó cung cấp một cải tiến hiệu suất ( vì nó có thể thoát ngay khi tìm thấy kết quả khớp đầu tiên ) [...]

Bây giờ, theo cùng một tiêu chuẩn (trong phần Giới thiệu , trong INPUT PHIM )

Khi tiện ích tiêu chuẩn đọc tệp đầu vào có thể tìm kiếm và chấm dứt mà không có lỗi trước khi đến cuối tệp, tiện ích phải đảm bảo rằng tệp bù trong mô tả tệp mở được đặt đúng vị trí vừa qua byte cuối được xử lý bởi tiện ích [. ..]

tail -n +2 file
(sed -n 1q; cat) < file
...

Lệnh thứ hai tương đương với lệnh đầu tiên khi tệp có thể tìm kiếm được.


Tại sao grep -qtiêu thụ toàn bộ tập tin?


Đây là gnu grepnếu nó quan trọng (mặc dù Kusalananda chỉ xác nhận điều tương tự xảy ra trên OpenBSD)


OpenBSD greplà một nhánh của một thứ gọi là FreeGrep , nếu có ai thắc mắc.
Kusalananda

Câu trả lời:


37

grep không dừng lại sớm, nhưng nó đệm đầu vào của nó để bài kiểm tra của bạn quá ngắn (và vâng, tôi nhận ra bài kiểm tra của mình không hoàn hảo vì không thể tìm kiếm được):

seq 1 10000 | (grep -q 2; cat)

bắt đầu từ 6776 trên hệ thống của tôi. Điều đó phù hợp với bộ đệm 32KiB được sử dụng theo mặc định trong GNU grep:

seq 1 6775 | wc

đầu ra

   6775    6775   32768

Lưu ý rằng POSIX chỉ đề cập đến cải tiến hiệu suất

Khi tìm kiếm một số tập tin

Điều đó không đặt ra bất kỳ kỳ vọng nào về cải tiến hiệu suất do đọc một phần một tệp.


2

Điều này rõ ràng là do bộ đệm greplàm tăng tốc mọi thứ. Có những công cụ được thiết kế đặc biệt để đọc nhiều ký tự theo yêu cầu và không còn nữa. Một trong số đó là expect:

{ expect -c "log_user 0; expect 2"; cat; } < infile

Tôi không có hệ thống để thử cái này, nhưng tôi tin rằng expectsẽ ăn hết mọi thứ cho đến khi nó gặp chuỗi dự kiến ​​( 2), rồi chấm dứt, để lại phần còn lại của đầu vào cat.


1

Bạn đang nhầm lẫn sed và grep.

Đối với lệnh sed, -2qđang nói thoát khỏi vòng lặp hiện tại nếu ở dòng thứ hai, -ntùy chọn đang nói là hoạt động lặng lẽ, vì vậy bạn sẽ nhận được tất cả các dòng sau lần thứ 2.

Lệnh grep chạy theo mặc định để xuất tất cả các dòng khớp - nhưng -qtùy chọn nói không xuất bất cứ thứ gì ra thiết bị xuất chuẩn. vì vậy, nếu đầu vào chứa "2", nó sẽ có giá trị thoát là THÀNH CÔNG, nếu không thì KHÔNG CÓ. Những gì được phụ thuộc vào hệ điều hành và vỏ của bạn. Vì vậy, thông thường bạn sẽ biết liệu một dòng có khớp hay không bằng cách kiểm tra giá trị thoát của quy trình grep. Điều này rất hữu ích trong một đường ống mà bạn muốn biết liệu đầu vào của bạn có chứa một số giá trị dưới dạng thử nghiệm hay không. Ví dụ

if grep -q 'crash' <somelog.log ; then report_crash_via_email ; fi

Trong trường hợp này, chúng tôi thực sự không quan tâm để xem tất cả các dòng khớp, chúng tôi chỉ quan tâm nếu có ít nhất một dòng tồn tại. Các report_crash_via_emailquy trình / chức năng sau đó có thể đi tắt và mở lại tập tin, hay không.

Nếu bạn muốn quy trình grep của mình DỪNG sau khi nó tìm thấy ký tự "2" - nó sẽ không mặc định, nó sẽ kiểm tra mọi dòng tìm xem nó có khớp không - bạn cần yêu cầu nó làm điều đó. Chuyển đổi dòng lệnh cho đó là -m <value>. Vì vậy, đối với trường hợp của bạn , grep -q -m1 2.


6
Câu trả lời của bạn là thông tin hữu ích cho việc sử dụng chung grepnhưng câu hỏi này là hỏi về một cái gì đó tinh tế và bí truyền hơn. Có vẻ như bạn đã đọc câu hỏi quá nhanh để hiểu hành vi thực tế đang được truy vấn. Ngoài ra, GNU grep không dừng tìm kiếm khi được sử dụng với -q(như được cho phép trong trích dẫn từ đặc tả POSIX): Trang man cho GNU grep nói rằng nó Thoát Thoát ngay lập tức với trạng thái bằng 0 nếu tìm thấy bất kỳ kết quả khớp nào . FWIW, tôi đã chỉnh sửa câu hỏi của bạn để cho thấy cách bạn có thể định dạng các bài đăng trong tương lai. Chào mừng đến với trao đổi ngăn xếp .
Anthony G - công lý cho Monica

Điều đó nói rằng, câu trả lời của @ user212377 là chính xác: trong trường hợp grepnày đang được hỏi nếu '2' tồn tại trong tệp, không có gì hơn và không có gì. Nó không hành xử như thế sedvà tiêu thụ các hồ sơ cho đến thời điểm đó và để lại phần còn lại để xử lý tiếp. Nó đọc cho đến khi biết có "2" hoặc không có, đóng tệp và trả về kết quả.
Keith Davies

greptrong thực tế chỉ 'tiêu thụ toàn bộ tệp' (bỏ qua các cân nhắc đệm) nếu chuỗi tìm kiếm không có trong tệp (điều này chỉ có thể chứng minh bằng cách kiểm tra toàn bộ tệp). Bất cứ điều gì ít hơn thế, việc đọc tệp dừng lại , tệp được đóng lại và THÀNH CÔNG được trả về.
Keith Davies
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.