xargs에서 인수가 전달되면 첫 번째 일치 후 Zgrep이 중지됩니다.

xargs에서 인수가 전달되면 첫 번째 일치 후 Zgrep이 중지됩니다.

나는 이 명령을 사용하여 여기에 제안된 zip 파일(하나와 유사)의 패턴을 찾습니다. https://superuser.com/questions/144926/unix-grep-for-a-string-within-all-gzip-files-in-all-subdirectories

find . -regex ".*/.*zip" | xargs zgrep -m 1 -E "PATTERN"

Grepping은 첫 번째 경기 이후에도 계속됩니다. 아마도 find/ xargs가 범인일 것이다. 첫 번째 일치 항목을 찾은 후 찾기를 중지하는 방법은 무엇입니까 grep?

추신첫 번째 일치 후 find 명령을 중지하는 방법은 무엇입니까?findfind의 첫 번째 일치뿐만 아니라 grep에 성공한 일치 후에 중지해야 하기 때문에 작동하지 않습니다 .

답변1

몇 가지 사항:

  • zgrep압축된 아카이브 안의 파일이 아닌, 압축된 파일을 .z들여다 보는 것입니다 ..gzzip

    zipgrep때때로 아카이브를 unzip조사하기 위해 와 함께 번들로 제공되는 (깨진) 스크립트가 있지만 이 스크립트 zip가 수행하는 작업은 egrep아카이브의 각 구성원에서 실행됩니다(따라서 -m1각각은 egrep각 파일에 대한 첫 번째 일치 항목을 보고합니다).

    zgrep, 마찬가지로 각 파일에 대한 출력 gzip을 제공하는 스크립트도 함께 제공됩니다 . 파일 의 압축을 풀 수 있지만 아카이브의 첫 번째 구성원과 압축된 경우에만 그렇게 합니다( 파일에서 모든 구성원이 반드시 압축되는 것은 아니며, 특히 작은 구성원).gzip -cdfqgrepgzip -dzipzip

  • xargs필요한만큼 적은 수의 명령을 실행하지만 파일 목록이 큰 경우 여러 명령을 계속 실행할 수 있습니다.

여기서 가장 좋은 방법은 아마도 zipgrep직접 구현하는 것입니다(여기에서는 GNU 도구 사용).

find . -name '*.zip' -type f -exec sh -c '
    unzip -Z1 "$1" |
      while IFS= read -r file; do
        unzip -p "$1" "$file" | grep --label="$1//$file" -Hm1 -- "$0" && exit
      done' PATTERN {} \; -quit

이는 파일당 하나의 쉘을 실행하지만 더 많은 명령을 실행합니다 zipgrep.zipgrep

아카이브 구성원의 이름에 와일드카드 문자( *, [, ?)나 ASCII 문자 0x1~0x1f 및 기타 다양한 문자가 포함된 경우 실패할 수 있지만 이는 대부분 의 버그 및 제한 사항으로 인한 것이며 unzip를 사용할 때만큼 나쁘지는 않습니다 zipgrep.

답변2

노력하다:

find . -iname '*.zip' -print0 | xargs -0r zgrep -l -E 'PATTERN'

-iname나는 오히려 이것을 사용했습니다 -regex. 이것은 이것에도 잘 작동하며 IMO find의 이상한 정규식 처리보다 덜 혼란스럽습니다. 공백이나 셸 메타 문자가 포함된 파일 이름이 올바르게 처리되도록 하기 위해 사용됩니다 -print0.xargs -0

grep-l옵션은 매뉴얼 페이지에 문서화되어 있습니다:

   -l, --files-with-matches
          Suppress  normal  output;  instead  print the name of each input
          file from which output would normally have  been  printed.   The
          scanning  will  stop  on  the  first match.

언급된 첫 번째 일치는 파일별로 이루어지므로 여러 파일이 일치하면 모두 인쇄됩니다. 이는 grep이 일치하는 파일을 찾은 후에도 다른 파일을 계속 검색한다는 것을 의미합니다.

첫 번째 일치 후에 중지하려면 grep--line-buffered옵션을 사용하고 grep의 출력을 head -1. 첫 번째 일치 항목이 인쇄되면 head인쇄하고 종료하며 grep더 이상 stdout이 없으므로 종료되고 find뒤따릅니다.

find . -iname '*.zip' -print0 | xargs -0r zgrep --line-buffered -l -E 'PATTERN' | head -1

답변3

grep의 (또는 zgrep의) -m옵션을 사용하면 읽기가 중단됩니다.현재 파일첫 경기에서:

   -m NUM, --max-count=NUM
          Stop reading a file after NUM matching lines.  

그렇다고 해서 검색이 중단되지는 않습니다.다음파일. 예를 들어:

$ echo "hello" > foo
$ echo "hello" > bar
$ grep -m 1 hello foo bar
foo:hello
bar:hello

따라서 문제는 xargs여러 파일을 수집하고 있다는 사실이 아닙니다. 첫 번째 매칭 후 grep(또는 ) 중지 되도록 하려면zgrep파일, @Stephane이 제안한 것처럼 약간의 루프를 실행해야 합니다. 또는 bash를 사용하면 다음과 같습니다.

shopt -s globstar
for i in **/*.zip; do
  zgrep -l pattern "$i" && break; 
done

또는 다음과 같은 zip 아카이브의 경우여러 파일을 포함(@Stephane에게 감사드립니다):

shopt -s globstar
for i in **/*.zip; do
  if unzip -p "$i" | grep -q hello; then 
    echo "$i" && break;
  fi;
done

답변4

grep -m 1모든 파일의 첫 번째 일치 항목을 나열합니다.

첫 번째 일치 항목만 나열하는 쉬운 방법이 있습니다 head -n 1. 검색은 곧 중단될 것입니다.시그파이프.

find . -regex ".*/.*zip" -print0 | xargs -0 zgrep -E "PATTERN" | head -n 1

관련 정보