.gz 파일을 통해 재귀 적으로 grep하는 방법은 무엇입니까?


135

원시 .eml을 .gz 파일로 압축하는 Gmail 메시지를 정기적으로 다운로드하는 스크립트를 사용하고 있습니다. 이 스크립트는 매일 폴더를 만든 다음 모든 메시지를 자체 파일로 압축합니다.

이 아카이브에서 "문자열"을 검색하는 방법을 원합니다.

그렙만으로는 그렇게하지 않습니다. 나는 또한 SearchMonkey를 시도했다.


16
사용 zgrep:zgrep - search possibly compressed files for a regular expression
Arkadiusz Drabczyk

답변:


141

현재 디렉토리의 모든 .eml.gz 파일에서 재귀 적으로 grep하려는 경우 다음을 사용할 수 있습니다.

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

*쉘이 해석하지 않도록 첫 번째 탈출을해야 합니다. -print0찾은 각 파일 뒤에 널 문자를 인쇄하도록 find에 지시합니다. xargs -0표준 입력에서 읽고 각 파일에 대해 명령을 실행합니다. zgrep처럼 작동 grep하지만 파일을 먼저 압축 해제합니다.


2
'-print0'및 '-0'은 필수가 아닙니다. xargs는 기본적으로 '\ n'을 사용합니다.
Jaime M.

1
경로에 공백 문자가있을 경우 필요합니다. 그것들을 사용하지 않는 복잡성 외에 다른 이유는 없습니다.
Daniel Griscom

2
zgrepgrep압축되지 않은 파일에서 실행하는 것보다 실제로 더 빠릅니다 . 압축 파일을 HD에서 읽을 수 있고 HD에서 압축되지 않은 파일을 읽는 것보다 빠르게 압축을 풀 수 있기 때문입니다.
Geremia

@JaimeM. xargs사용 공백 기본적으로 (공백). 물론 파일에는 줄 바꿈이 거의 없지만 공백은 들어 있지 않습니다 (대부분의 UNIX 유형이 인상을 찌푸 리더라도). 즉, 공백에 대해 더 쉽게 걱정할 필요없이 단순화 할 수 있습니다. find . -name '*.eml.gz' -exec zgrep "STRING" {} +즉 , 추가 프로세스 실행 및 파이핑의 오버 헤드없이 상당히 많은 론칭 xargs, -print0/ 의 안전성 -0및 모든 인수를 얻을 수 있습니다 . -execwith +POSIX가 지정되었으므로 가장 반 유닉스와 유사한 시스템에 있어야합니다.
ShadowRanger

@Jared 파일 패턴의 시작 부분 만 알고 와일드 카드 검색을 수행하는 방법이 있습니까? 예를 들어 끝에 날짜 / 시간 스탬프가있는 .gz 파일이 있습니다. ABCLog04_18_18_2_21.gz ABC *로 시작하는 파일을 재귀 적으로 찾을 수있는 방법이 있습니까? \*.eml.gz위의 예에서 ABCLog*파일 형식으로 바꾸려고했지만 파일 형식에 대한 오류가 발생했습니다.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

하나만 없기 때문에 여기에 많은 혼란이 있습니다 zgrep. 나는 내 시스템에 두 가지 버전이 zgrep에서 gzipzgrep에서 zutils. 전자는 단지 호출하는 래퍼 스크립트입니다 gzip -cdfq. -r, --recursive스위치를 지원하지 않습니다 . 1
후자는 c++프로그램이며 옵션을 지원 합니다 -r, --recursive.
Running zgrep --version | head -n 1은 그들 중 어느 것이 기본값인지 알려줍니다 :

zgrep (gzip) 1.6

래퍼 스크립트입니다.

zgrep (zutils) 1.3

는 IS cpp실행 파일.
후자가 있으면 다음을 실행할 수 있습니다.

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

어쨌든 제안 된대로 find+ zgrepzgrep다음 버전 중 하나와 똑같이 잘 작동합니다 .

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

zgrep시스템에서 누락 된 경우 (아마도) 다음을 시도해보십시오.

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

그러나 큰 단점이 있습니다 : 일치하는 줄 앞에 파일 이름이 없기 때문에 일치하는 위치를 알 수 없습니다.


1 : 문제가되기 때문에


1
zgrepzutils에서 사용할 수없는 경우 와 함께 Ubuntu에 설치할 수 있습니다 sudo apt-get install zutils.
therealmarv

1
@therealmarv ...에서 계속하면 우분투는 gzip 대신 zutils zgrep을 사용합니다. 그럼 -r 작동합니다!
Elijah Lynn

패턴이 일치하는 파일의 줄 번호를 인쇄하는 방법이 있습니까?
DogEatDog

@DogEatDog-처럼 grep -n, zgrep -n라인 번호를 인쇄합니다. 매뉴얼에 ...
don_crissti

7

aggrep멋진 추가 기능 이있는의 변형입니다 .

  • 압축 파일에 -z 옵션이 있습니다.
  • 많은 ack 기능이 있습니다.
  • 빠르다

그래서:

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

설치되지 않은 경우

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

1
ag: truncated file: Success결과적으로 얻는다 . 다른 깃발을 추가해야합니까?
Yar

4

재귀만으로는 쉽습니다.

   -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.

그러나 압축 파일의 경우 다음과 같은 것이 필요합니다.

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

path/to/directory 매일 서브 디렉토리를 포함하는 상위 디렉토리 여야합니다.


zgrep명백한 대답이지만 불행히도 -r플래그를 지원하지 않습니다 . 보낸 사람 man zgrep:

이러한 grep 옵션을 사용하면 zgrep이 (-[d rR zZ] | --di * | --exc * | --inc * | --rec * | --nu *) 오류 코드와 함께 종료됩니다 .


3

시스템에 zgrep이있는 경우 간단히

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

시스템에 zgrep가없는 경우 find 명령을 사용하여 다음과 같이 각 파일에 대해 zcat 및 grep을 실행할 수 있습니다 .

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


이것에 대해 Greeness를 용서하십시오 ... 탐색 할 파일은 몇 층의 깊이입니다. ~ / gmvault-db / db / 2015-02에는 보관 된 각 달의 폴더가 포함되어 있으며 그 달의 .gz 파일이 저장됩니다. 전체 트리에서 .mil을 검색하면 어떻게해야합니까? ~ / gmvault-db / db / -name '* .gz'\ -exec sh -c 'echo "{}"검색; zcat "{}"| grep .mil '\;
Kendor

1
-irs의 "r"은 zgrep을 재귀 적으로 검색하게합니다. find 명령은 기본적으로 재귀 적으로 작동하므로 .gz로 끝나는 모든 파일은 zcatted되어 grep으로 전달됩니다. {}는 검색하려고하는 파일의 상대 경로로 확장됩니다. 그래서 당신이 명중을 얻을 때, 그것은 앞에 올 것이다 Searching ~/gmvault-db/db/2015-02/03/whatever.gz
네이트에서 Kalamazoo

다음은 내가 얻는 것입니다. 찾기 : "경로가 식 앞에 와야합니다 : -exec"다음은 내가 사용한 명령입니다 : find ~ / gmvault-db / db / -name '* .gz'\ -exec sh -c 'echo "{ } "; zcat "{}"| grep .mil '\;
Kendor

'* .gz'와 -exec 사이의 백 슬래시를 제거하십시오.
Kalamazoo에서 Nate

4
zgrep-r어떤 이유로 든 깃발을 가져 가지 않습니다 . man zgrep(내 대답 참조)에 언급되어 있습니다.
terdon

0

xzgrep -l "문자열"./*/*.eml.gz

xzgrep은 zgrep 유틸리티의 파생물입니다 (/ bin / xzgrep 이하).

매뉴얼 페이지에서 :

xzgrep는 xz (1), lzma (1), gzip (1), bzip2 (1) 또는 lzop (1)로 압축 또는 압축 될 수있는 파일에서 grep (1)을 호출합니다. 지정된 모든 옵션은 grep (1)으로 직접 전달됩니다.

-l 일치하는 파일 이름을 인쇄합니다

재귀에 대한 -R은 스크립트에서 특별히 금지되어 있기 때문에 작동하지 않지만 간단한 쉘 globbing은 우리를 거기에 도착시켜야합니다.

./*/*.eml.gz

./today/sample.eml.gz 인 상대 경로에서 쉘의 상대 위치보다 한 레벨 아래 인 ".eml.gz"로 끝나는 모든 인스턴스에서 일치합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.