Grep dòng dài nhất đầu tiên
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
Lệnh khó đọc một cách bất thường mà không cần thực hành vì nó trộn cú pháp shell- và regrec.
Để giải thích, tôi sẽ sử dụng mã giả đơn giản hóa trước. Các dòng bắt đầu ##
không chạy trong vỏ.
Mã đơn giản hóa này sử dụng tên tệp F và bỏ qua phần trích dẫn và các phần của biểu thức chính quy để dễ đọc.
Làm thế nào nó hoạt động
Lệnh này có hai phần, một grep
- và một lệnh wc
gọi:
## grep "^.{$( wc -L F )}$" F
Nó wc
được sử dụng trong một quá trình mở rộng $( ... )
, vì vậy nó được chạy trước đó grep
. Nó tính toán độ dài của dòng dài nhất. Cú pháp mở rộng shell được trộn với cú pháp mẫu biểu thức chính quy theo cách khó hiểu, vì vậy tôi sẽ phân tách quá trình mở rộng quy trình:
## wc -L F
42
## grep "^.{42}$" F
Ở đây, quá trình mở rộng đã được thay thế bằng giá trị mà nó sẽ trả về, tạo ra grep
dòng lệnh được sử dụng. Bây giờ chúng ta có thể đọc biểu thức chính quy dễ dàng hơn: Nó khớp chính xác từ start ( ^
) đến end ( $
) của dòng. Biểu thức giữa chúng khớp với bất kỳ ký tự nào ngoại trừ dòng mới, được lặp lại 42 lần. Kết hợp lại, đó là các dòng bao gồm chính xác 42 ký tự.
Bây giờ, quay lại các lệnh shell thực: grep
Tùy chọn -E
( --extended-regexp
) cho phép không thoát khỏi {}
khả năng đọc. Tùy chọn -m 1
( --max-count=1
) làm cho nó dừng lại sau khi dòng đầu tiên được tìm thấy. Lệnh <
trong wc
ghi ghi tệp vào stdin của nó, để ngăn không cho wc
in tên tệp cùng với độ dài.
Dòng nào dài nhất?
Để làm cho các ví dụ dễ đọc hơn với tên tệp xảy ra hai lần, tôi sẽ sử dụng một biến f
cho tên tệp; Mỗi $f
trong ví dụ có thể được thay thế bằng tên tệp.
f="file.txt"
Hiển thị dòng dài nhất đầu tiên - dòng đầu tiên dài bằng dòng dài nhất:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Hiển thị tất cả các dòng dài nhất - tất cả các dòng dài bằng dòng dài nhất:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Hiển thị dòng dài nhất cuối cùng - dòng cuối cùng dài bằng dòng dài nhất:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Hiển thị dòng dài nhất - dòng dài nhất dài hơn tất cả các dòng khác hoặc không thành công:
[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f"
(Lệnh cuối cùng thậm chí còn kém hiệu quả hơn các lệnh khác, vì nó lặp lại lệnh grep hoàn chỉnh. Rõ ràng nó phải được phân tách để đầu ra wc
và các dòng được viết bởi grep
các biến.
Lưu ý rằng tất cả các dòng dài nhất có thể thực sự là tất cả các dòng . Để lưu trong một biến, chỉ cần giữ hai dòng đầu tiên.)