Giới hạn đầu ra grep thành các dòng ngắn


8

Tôi thường sử dụng grep để tìm các tệp có một mục nhất định như thế này:

grep -R 'MyClassName'

Điều tốt là nó trả về các tệp, nội dung của chúng và đánh dấu chuỗi tìm thấy bằng màu đỏ. Điều tệ hại là tôi cũng có các tệp lớn trong đó toàn bộ văn bản được viết thành một dòng lớn. Bây giờ grep xuất quá nhiều khi tìm văn bản trong các tệp lớn đó. Có cách nào để giới hạn đầu ra ví dụ 5 từ bên trái và bên phải không? Hoặc có thể giới hạn đầu ra ở 30 chữ cái bên trái và bên phải?


3
Kết quả của bạn thông quacut
Rinzwind

Vì vậy, giả sử mẫu bạn đang tìm kiếm ở vị trí 50, nhưng bạn nói bạn chỉ muốn 30 chữ cái. Bạn muốn làm gì sau đó? Bỏ qua dòng đó hoặc cũng bao gồm nó vào đầu ra nhưng cắt nó? Chính xác những gì bạn muốn giới hạn - tìm kiếm hoặc chính các dòng?
Sergiy Kolodyazhnyy

1
@Rinzwind Tôi không hiểu lắm về những gì bạn muốn đạt được cut, vì nó chỉ phân tách theo dấu phân cách hoặc theo số lượng ký tự. Mặc dù khi tôi tìm thấy một dòng với MyClassNamenó có thể là bất cứ nơi nào trong dòng và không phải lúc nào cũng ở cùng một vị trí. Hơn nữa, có thể có một biến thể của các ký tự ở phía trước và phía sau của nó, phá vỡ khả năng phân tách bằng dấu phân cách.
Socrates

1
@SergiyKolodyazhnyy Khi MyClassNametìm thấy một dòng tích cực , tôi muốn nhận được kết quả là tên tệp và ký tự x ở bên trái và bên phải. x là bất kỳ số nào tôi cung cấp, ví dụ 30. Phần còn lại của nội dung tệp sẽ bị bỏ qua. Điều này là để có được một bối cảnh cho các tập tin phù hợp và hạn chế quá tải.
Socrates

1
@Rinzwind loại gì về dấu phân cách tùy chỉnh bạn sẽ đề nghị với cutnếu có ba file với đầu vào sau: oiadfaosuoianavMyClassNameionaernaldfajd/(/&%%§%/(§(/MyClassName&((/$/$/(§/$&public class MyClassName { public static void main(String[] args) { } }?
Socrates

Câu trả lời:


15

grepbản thân nó chỉ có các tùy chọn cho bối cảnh dựa trên các dòng. Một thay thế được đề xuất bởi bài SU này :

Cách giải quyết là cho phép tùy chọn 'chỉ khớp' và sau đó sử dụng sức mạnh của RegExp để grep nhiều hơn một chút so với văn bản của bạn:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}" ./filepath

Tất nhiên, nếu bạn sử dụng tô sáng màu, bạn luôn có thể grep lại để chỉ tô màu khớp chính xác:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}"  ./filepath | grep "WHAT_I_M_SEARCHING"

Thay vào đó, tôi khuyên bạn foldnên lấy văn bản và sau đó greping nó, ví dụ:

fold -sw 80 input.txt | grep ...

Các -stùy chọn sẽ làm cho foldlời đẩy vào dòng tiếp theo thay vì phá vỡ ở giữa.

Hoặc sử dụng một số cách khác để phân chia đầu vào theo dòng dựa trên cấu trúc của đầu vào của bạn. (Ví dụ, bài viết SU đã xử lý JSON, do đó, sử dụng jqvv để in đẹp và grep... hoặc chỉ sử dụng jqđể tự lọc ... sẽ tốt hơn một trong hai phương án được đưa ra ở trên.)


Phương pháp awk GNU này có thể nhanh hơn:

gawk -v n=50 -v RS='MyClassName' '
  FNR > 1 { printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)}
  {p = substr($0, length - n); prt = RT}
' input.txt
  • Yêu cầu awk phân chia các bản ghi trên mẫu mà chúng ta quan tâm ( -v RS=...) và số lượng ký tự trong ngữ cảnh ( -v n=...)
  • Mỗi bản ghi sau bản ghi đầu tiên ( FNR > 1) là một trong đó awk tìm thấy một kết quả khớp cho mẫu.
  • Vì vậy, chúng tôi in ncác ký tự theo dõi từ dòng trước ( p) và ncác ký tự đầu từ dòng hiện tại ( substr($0, 0, n)), cùng với văn bản phù hợp cho dòng trước đó (đó là prt)
    • chúng tôi đặt pprt sau khi in, vì vậy giá trị chúng tôi đặt được sử dụng bởi dòng tiếp theo
    • RT là một GNUism, đó là lý do tại sao đây là GNU awk-cụ thể.

Đối với tìm kiếm đệ quy, có thể:

find . -type f -exec gawk -v n=50 -v RS='MyClassName' 'FNR>1{printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)} {p = substr($0, length-n); prt = RT}' {} +

2
Ok, nó hoạt động. Có vẻ như Regex là một cách tiếp cận hợp lệ, vì vậy cảm ơn vì điều đó. Thời gian xử lý là khá lớn mặc dù. Không có Regex như trong bài viết trên của tôi, phải mất 4.912 giây và với Regex như trong bài viết của bạn, phải mất 339.312 giây.
Socrates

1
@Socrates xem phương thức awk tôi đã thêm ở trên có hoạt động tốt hơn không
muru

1
Các foldphương pháp có thể được sử dụng chỉ khi bạn chắc chắn rằng đã tìm kiếm các chuỗi không xuất hiện tại biên giới, nếu không nó sẽ bị ẩn bởi grep.
Melebius

1
@muru Cảm ơn lời đề nghị của bạn với gawk. Thật không may, lệnh được đề xuất với findđầu ra ngẫu nhiên và không có tên tệp, khi được thực thi trên hệ thống của tôi. Hơn nữa, tôi không đủ thông thạo awkđể phân tích đúng lệnh. Hiện tại, Regex kết hợp với grepgiải quyết vấn đề có thể không nhanh, nhưng đáng tin cậy. Một lần nữa, cảm ơn rất nhiều.
Socrates

1
@Socrates Tôi nghĩ rằng tôi đã quản lý để sửa lệnh awk. Mô hình tinh thần của tôi đã sai về việc sử dụng dòng nào RTvà tiền tố, v.v.
muru

1

Sử dụng chỉ kết hợp kết hợp với một số tùy chọn khác (xem bên dưới), có thể rất gần với những gì bạn đang tìm kiếm, mà không có chi phí xử lý của regex được đề cập trong câu trả lời khác

grep -RnHo 'MyClassName'
  • n đầu ra số, hiển thị số dòng của trận đấu
  • Tên tệp H , hiển thị tên tệp ở đầu dòng khớp
  • o chỉ khớp, chỉ hiển thị chuỗi toán học, không hiển thị toàn bộ dòng

Mặc dù đúng là kết quả được tìm thấy nhanh hơn nhiều, nhưng vẫn thiếu thông tin. Đường dẫn tệp được hiển thị, số dòng được hiển thị, nhưng đầu ra văn bản chỉ là tìm kiếm ban đầu của tôi MyClassName. Do đó, bối cảnh bị thiếu.
Socrates

grep -RnHo "MyClassName"grep -Rno "MyClassName"có cùng một đầu ra.
Socrates

Đầu ra @Socrates không giống nhau nếu không có H trong cùng thư mục
Robert Riedl

Các -olá cờ có thể là thú vị nếu regex đã có một số phần biến. Đối với một chuỗi cố định, việc in nó mỗi lần là vô ích. OP rất có thể quan tâm đến bối cảnh gần.
Melebius

1
@Socrates, đúng - bối cảnh bị thiếu, nhưng tôi nghĩ đó là điểm? Hạn chế đầu ra? Bạn có thể thêm ngữ cảnh một lần nữa bằng cách thêm các dòng trước ( -B 1) hoặc sau ( -A 1). Xin lỗi rằng tôi không thể giúp đỡ nhiều hơn.
Robert Riedl
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.