조회 출력을 제한하고 신호 13을 방지합니다.

조회 출력을 제한하고 신호 13을 방지합니다.

특정 패턴을 검색하는 데 필요한 약 1M 파일이 포함된 디렉토리가 있습니다. 나는 모든 파일에 대해 이 작업을 수행하는 방법을 알고 있습니다.

find /path/ -exec grep -H -m 1 'pattern' \{\} \;

전체 출력이 필요하지 않습니다(너무 느림). 처음 몇 번 클릭하면 효과가 있었으므로 행 수를 제한해 보았습니다.

find /path/ -exec grep -H -m 1 'pattern' \{\} \; | head -n 5

이렇게 하면 5개의 라인이 생성되고 그 다음에는

find: `grep' terminated by signal 13

그리고 find계속 일하세요. 이건 설명하기 쉽죠여기. 나는 quit행동을 시도했다:

find /path/ -exec grep -H -m 1 'pattern' \{\} \; -quit

이는 첫 번째 일치 항목만 출력합니다.

찾기 출력을 특정 수의 결과로 제한할 수 있습니까(예: quitsimple to 와 유사한 매개변수 제공 head -n)?

답변1

-quit이미 GNU 확장( , -H, ) 을 사용하고 있으므로 GNU 옵션을 사용 하여 일치 항목을 찾는 즉시 출력하도록 -m1할 수도 있습니다 . 따라서 일치 항목이 발견되면 SIGPIPE에 의해 종료될 가능성이 더 높습니다. 6번째 줄은 다음과 같습니다.grep-r--line-buffered

grep -rHm1 --line-buffered pattern /path | head -n 5

의 경우 find다음을 수행해야 할 수도 있습니다.

find /path -type f -exec sh -c '
  grep -Hm1 --line-buffered pattern "$@"
  [ "$(kill -l "$?")" = PIPE ] && kill -s PIPE "$PPID"
  ' sh {} + | head -n 5

즉, 래핑하고 grep( 여전히 가능한 적은 호출을 sh실행하고 싶으 므로 그렇습니다), SIGPIPE로 인해 종료되면 해당 부모( )를 종료합니다 .grep{} +shfindgrep

또 다른 접근 방식은 생성된 명령이 신호로 인해 종료될 때 즉시 xargsas.exit를 사용하는 것입니다 -exec {} +.xargs

 find . -type f -print0 |
   xargs -r0 grep -Hm1 --line-buffered pattern |
   head -n 5

( -r그리고 -0GNU 확장입니다). grep손상된 파이프에 쓰기가 수행 되면 둘 다 종료 grep되고 다음에 무언가가 인쇄될 때도 자체적으로 종료됩니다. 달리면 더 빨리 일어날 수 있습니다.xargsfindfindstdbuf -oL

POSIX 버전은 다음과 같습니다.

trap - PIPE # restore default SIGPIPE handler in case it was disabled
RE=pattern find /path -type f -exec sh -c '
  for file do
    awk '\''
      $0 ~ ENVIRON["RE"] {
        print FILENAME ": " $0
        exit
      }'\'' < "$file"
    if [ "$(kill -l "$?")" = PIPE ]; then
      kill -s PIPE "$PPID"
      exit
    fi
  done' sh {} + | head -n 5

파일당 여러 명령을 실행하므로 매우 비효율적입니다.

답변2

오류를 방지하는 솔루션은 다음과 같습니다.

find / -type f -print0 \
  | xargs -0 -L 1 grep -H -m 1 --line-buffered 2>/dev/null \
  | head -10

이 예에서는 명령이 실패하면 xargs가 중지되므로 파이프 오류만 발생하며 이는 stderr 리디렉션에 의해 필터링됩니다.

답변3

grep한 번에 하나의 파일을 작업합니다 . 귀하의 것을 사용하면 -quit첫 번째 성공적인 grep에서 검색을 중지할 수 있습니다.

[업데이트] 내 첫 번째 솔루션은 한 번에 여러 파일을 grep하는 것이었습니다.

find /path/ -type f -exec grep -H -m 1 'pattern' \{\} + -quit | head -n 5

(마법은 하위 명령 끝에 . 을 추가하는 것입니다 +. /path/에 여러 파일이 포함되어 있다고 확신하는 경우 이 옵션을 제거할 수 있습니다)-exec-type f-Hgrep

@StéphaneChazelas가 보고한 대로 여기서 문제는 -exec명령이 비동기식으로 실행되고 항상 첫 번째 파일에서 true=> 종료를 반환한다는 것입니다.find

완료 시 중지 하려면 find수신 중인 SIGPIPE도 수신해야 합니다(신호 13). 이는 파이프를 통해 무언가를 전송해야 함을 의미합니다.headfindgrepfind

다음은 Stéphane의 제안을 기반으로 향상된 빠르고 더러운 트릭입니다.

find /path/ -type f -exec grep -H -m 1 --line-buffered 'pattern' {} + -printf '\r' | head -n 5

출력을 무해한 문자로 -printf '\r'강제하면 출력 이 변경되지 않기를 바랍니다 . 중지 되면 SIGPIPE가 수신되어 중지됩니다.findgrepheadfind

[업데이트 2] 나는 이것이 더러운 해킹이라고 경고했습니다. 더 나은 해결책은 다음과 같습니다.

find /path/ -type f -exec grep --quiet 'pattern' {} ";" -print | head -n 5

여기서는 더 이상 grep파일 이름을 인쇄 하지 않지만 find=> 더 이상 "grep은 신호 13에 의해 종료되었습니다" find로 끝나지 않습니다 head. 문제는 일치하는 행이 더 이상 인쇄되지 않는다는 것입니다 grep.

[update3] 마지막으로 @Andrey가 제안한 것처럼 아래의 뻔뻔스럽고 추악한 명령은 마지막 문제를 해결할 것입니다.

find /path/ -type f \
    -exec grep --quiet 'pattern' {} \; \
    -printf '%p:' \
    -exec grep -h -m 1 'pattern' {} \; \
| head -n 5`

답변4

더 간단한 경우 대체 경로는 파이프 대신 문자열일 수 있습니다. 예를 들어-

find . -exec stat -c %y {} \; | head -n1

위와 같은 문제를 보게 될 것입니다. 고려하는 간단한 방법 -

head -n1 <<<$(find . -exec stat -c %y {} \;)

관련 정보