Lý do tại sao
tac file | grep foo | head -n 1
Không dừng lại ở trận đấu đầu tiên là vì bộ đệm.
Thông thường, head -n 1
thoát sau khi đọc một dòng. Vì vậy, grep
nên lấy SIGPIPE và thoát cũng như ngay khi nó viết dòng thứ hai.
Nhưng điều xảy ra là bởi vì đầu ra của nó không đi đến một thiết bị đầu cuối, nên grep
đệm nó. Đó là, nó không viết nó cho đến khi nó tích lũy đủ (4096 byte trong thử nghiệm của tôi với GNU grep).
Điều đó có nghĩa là nó grep
sẽ không thoát ra trước khi nó đã ghi 8192 byte dữ liệu, vì vậy có lẽ khá nhiều dòng.
Với GNU grep
, bạn có thể làm cho nó thoát ra sớm hơn bằng cách sử dụng --line-buffered
nó để ghi nó ngay khi chúng được tìm thấy bất kể có đi đến thiết bị đầu cuối hay không. Vì vậy, grep
sau đó sẽ thoát khỏi dòng thứ hai nó tìm thấy.
Nhưng với GNU grep
dù sao đi nữa, bạn có thể sử dụng -m 1
thay vì như @terdon đã hiển thị, sẽ tốt hơn khi nó thoát ở trận đấu đầu tiên.
Nếu bạn grep
không phải là GNU grep
, thì bạn có thể sử dụng sed
hoặc awk
thay vào đó. Nhưng tac
là một lệnh GNU, tôi nghi ngờ bạn sẽ tìm thấy một hệ thống với tac
nơi grep
không phải là GNU grep
.
tac file | sed "/$pattern/!d;q" # BRE
tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE
Một số hệ thống phải tail -r
làm điều tương tự như GNU tac
.
Lưu ý rằng, đối với các tệp thông thường (có thể tìm kiếm) tac
và tail -r
hiệu quả vì chúng đọc các tệp ngược, chúng không chỉ đọc tệp đầy đủ trong bộ nhớ trước khi in ngược (như cách tiếp cận sed của @ slm hoặc tac
trên các tệp không thông thường) .
Trên các hệ thống không có sẵn tac
hoặc không tail -r
có sẵn, các tùy chọn duy nhất là triển khai đọc ngược bằng tay với các ngôn ngữ lập trình như perl
hoặc sử dụng:
grep -e "$pattern" file | tail -n1
Hoặc là:
sed "/$pattern/h;$!d;g" file
Nhưng những điều đó có nghĩa là tìm tất cả các trận đấu và chỉ in cái cuối cùng.