Làm cách nào để grep đệ quy thông qua các tệp .gz?


135

Tôi đang sử dụng tập lệnh để thường xuyên tải xuống các tin nhắn gmail của mình để nén .eml thô thành các tệp .gz. Kịch bản tạo một thư mục cho mỗi ngày, sau đó nén mọi tin nhắn vào tệp riêng của nó.

Tôi muốn một cách để tìm kiếm thông qua kho lưu trữ này cho một "chuỗi."

Grep một mình không xuất hiện để làm điều đó. Tôi cũng đã thử SearchMonkey.


16
sử dụng zgrep:zgrep - search possibly compressed files for a regular expression
Arkadiusz Drabchot

Câu trả lời:


141

Nếu bạn muốn grep đệ quy trong tất cả các tệp .eml.gz trong thư mục hiện tại, bạn có thể sử dụng:

find . -name \*.eml.gz -print0 | xargs -0 zgrep "STRING"

Bạn phải thoát cái đầu tiên *để cái vỏ không diễn giải nó. -print0bảo tìm in một ký tự null sau mỗi tệp mà nó tìm thấy; xargs -0đọc từ đầu vào tiêu chuẩn và chạy lệnh sau nó cho mỗi tệp; zgrephoạt động như thế grep, nhưng giải nén tập tin trước.


2
'-print0' và '-0' không bắt buộc. xargs sử dụng '\ n' theo mặc định.
Jaime M.

1
Chúng cần thiết nếu có thể có các ký tự không gian trong các đường dẫn; không có lý do nào khác ngoài sự phức tạp không sử dụng chúng.
Daniel Griscom

2
zgrepthực sự có vẻ nhanh hơn grepchạy trên các tập tin không nén. Đó phải là vì các tệp nén có thể được đọc khỏi HD và được giải nén nhanh hơn so với đọc một tệp không nén từ HD.
Lão máu

@JaimeM. xargssử dụng khoảng trắng (khoảng trắng) theo mặc định. Chắc chắn, các tệp hầu như không bao giờ có dòng mới trong chúng, nhưng không gian không phải là chưa từng thấy (ngay cả khi hầu hết các loại UNIXy đều nhăn mặt trên chúng). Điều đó nói rằng, bạn có thể đơn giản hóa mà không phải lo lắng về khoảng trắng thậm chí còn dễ dàng hơn: find . -name '*.eml.gz' -exec zgrep "STRING" {} +Điều đó có cùng nhiều đối số cho mỗi lần khởi chạy xargs, sự an toàn của -print0/ -0và tất cả mà không cần chi phí cho quá trình khởi động và đường ống bổ sung, và khá chính xác. -execvới +POSIX được chỉ định, do đó, nó phải có trên hầu hết các hệ thống giống như UNIX gần đây theo hiểu biết của tôi.
ShadowRanger

@Jared Có cách nào để thực hiện tìm kiếm ký tự đại diện chỉ khi biết bắt đầu mẫu tệp không? Ví dụ: tôi có các tệp .gz có dấu ngày / thời gian ở cuối chúng. ABCLog04_18_18_2_21.gz Có cách nào để tìm đệ quy các tệp bắt đầu bằng ABC *. Tôi đã cố gắng thay thế \*.eml.gztrong ví dụ của bạn ở trên với ABCLog*và nhận được một lỗi về định dạng tập tin .:find: paths must precede expression: ABCLog-2018-03-12-10-16-1.log.gz Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
DevelopingDeveloper

68

Có rất nhiều nhầm lẫn ở đây vì không chỉ có một zgrep. Tôi có hai phiên bản trên hệ thống của mình, zgreptừ gzipzgreptừ zutils. Các cựu chỉ là một kịch bản bao bọc mà gọi gzip -cdfq. Nó không hỗ trợ -r, --recursivechuyển đổi. 1
Sau đó là một c++chương trình và nó hỗ trợ các -r, --recursivetùy chọn.
Chạy zgrep --version | head -n 1sẽ tiết lộ cái nào (nếu có) trong số chúng là mặc định:

zgrep (gzip) 1.6

là tập lệnh bao bọc,

zgrep (zutils) 1.3

cppthực thi.
Nếu bạn có cái sau bạn có thể chạy:

zgrep 'pattern' -r --format=gz /path/to/dir

Dù sao, như đã đề xuất, find+ zgrepsẽ hoạt động tốt như nhau với cả hai phiên bản zgrep:

find /path/to/dir -name '*.gz' -exec zgrep -- 'pattern' {} +

Nếu zgrepbị thiếu trong hệ thống của bạn (rất khó xảy ra), bạn có thể thử với:

find /path/to/dir -name '*.gz' -exec sh -c 'gzip -cd "$0" | grep -- "pattern"' {} \;

nhưng có một nhược điểm lớn: bạn sẽ không biết các trận đấu diễn ra ở đâu vì không có tên tệp nào được đặt trước các dòng khớp.


1: bởi vì nó sẽ có vấn đề


1
nếu zgreptừ zutils không có sẵn, bạn có thể cài đặt nó trong Ubuntu với sudo apt-get install zutils.
Therealmarv

1
Tiếp tục từ @therealmarv ... và sau đó Ubuntu sẽ sử dụng zgrep zutils thay vì gzip. Sau đó -r hoạt động!
Elijah Lynn

Có cách nào để in số dòng của tệp mà mẫu được khớp không?
DogEatDog

@DogEatDog - giống như grep -n, zgrep -nsẽ in dòng no.s. Nó có trong hướng dẫn ...
don_crissti

7

aglà một biến thể của grep, với một số tính năng bổ sung tốt đẹp.

  • có tùy chọn -z cho các tệp nén,
  • có nhiều tính năng ack.
  • nó nhanh

Vì thế:

ag -r -z your-pattern-goes-here   folder

Nếu không được cài đặt,

apt-get install silversearcher-ag   (debian and friends)
yum install the_silver_searcher     (fedora)
brew install the_silver_searcher    (mac)

1
Tôi nhận được ag: truncated file: Successkết quả. Bất kỳ cờ nào khác tôi nên thêm?
Yar

4

Đệ quy một mình là dễ dàng:

   -r, --recursive
          Read all files  under  each  directory,  recursively,  following
          symbolic  links  only  if they are on the command line.  This is
          equivalent to the -d recurse option.

   -R, --dereference-recursive
          Read all files under each directory,  recursively.   Follow  all
          symbolic links, unlike -r.

Tuy nhiên, đối với các tệp nén, bạn cần một cái gì đó như:

shopt globstar 
for file in /path/to/directory/**/*gz; do zcat ""$file" | grep pattern; done

path/to/directory nên là thư mục mẹ chứa các thư mục con cho mỗi ngày.


zgreplà câu trả lời rõ ràng nhưng thật không may, nó không hỗ trợ -rcờ. Từ man zgrep:

Các tùy chọn grep này sẽ khiến zgrep chấm dứt với mã lỗi: (- [d rR zZ] | --di * | --exc * | --inc * | --rec * | --nu *).


3

Nếu hệ thống của bạn có zgrep, bạn có thể chỉ cần

zgrep -irs your-pattern-goes-here the-folder-to-search-goes-here/

Nếu hệ thống của bạn không có zgrep, bạn có thể sử dụng lệnh find để chạy zcat và grep đối với từng tệp như sau:

find the-folder-to-search-goes-here/ -name '*.gz' \ -exec sh -c 'echo "Searching {}" ; zcat "{}" | grep your-pattern-goes-here ' \;


Xin thứ lỗi cho tôi về điều này ... các tập tin được tìm kiếm là một vài lớp sâu. ~ / gmvault-db / db / 2015-02 chứa một thư mục cho mỗi tháng được lưu trữ và sau đó bên dưới các tệp .gz cho tháng đó được lưu trữ. Nếu tôi đang tìm kiếm .mil trong toàn bộ cây đó, đó có phải là điều tôi sẽ làm không? tìm ~ / gmvault-db / db / -name '* .gz' \ -exec sh -c 'echo "Tìm kiếm {}"; zcat "{}" | grep .mil '\;
Kendor

1
Điều đó tốt - các "r" in -irs sẽ khiến zgrep tìm kiếm đệ quy. Lệnh find hoạt động theo cách đệ quy theo mặc định, do đó, bất kỳ tệp nào kết thúc bằng .gz sẽ được zcatted và chuyển vào grep. (và {} sẽ được mở rộng đến đường dẫn tương đối của tệp sắp được tìm kiếm). Vì vậy, khi bạn nhận được một hit, nó sẽ được bắt đầu bởi Searching ~/gmvault-db/db/2015-02/03/whatever.gz
Nate từ Kalamazoo

Đây là những gì tôi nhận được: find: "đường dẫn phải đi trước biểu thức: -exec" Đây là lệnh tôi đã sử dụng: find ~ / gmvault-db / db / -name '* .gz' \ -exec sh -c 'echo "Tìm kiếm { } "; zcat "{}" | grep .mil '\;
Kendor

loại bỏ dấu gạch chéo ngược giữa '* .gz' và -exec.
Nate từ Kalamazoo

4
zgrepSẽ không lấy -rcờ vì một số lý do. Đó là đề cập đến man zgrep(cũng xem câu trả lời của tôi).
terdon

0

xzgrep -l "chuỗi" ./*/*.eml.gz

xzgrep là một dẫn xuất của các tiện ích zgrep (ít hơn / bin / xzgrep)

Từ trang Man:

xzgrep gọi grep (1) trên các tệp có thể không nén hoặc nén bằng xz (1), lzma (1), gzip (1), bzip2 (1) hoặc lzop (1). Tất cả các tùy chọn được chỉ định được chuyển trực tiếp đến grep (1).

-l in tên tập tin phù hợp

-R cho phép đệ quy sẽ không hoạt động vì nó bị cấm đặc biệt trong tập lệnh, tuy nhiên việc tạo lớp vỏ đơn giản sẽ đưa chúng ta đến đó

./*/*.eml.gz

từ một đường dẫn tương đối trong đó

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.