여러 파일에서 문자열을 검색하고 해당 파일 이름의 모든 항목을 나열하는 방법

여러 파일에서 문자열을 검색하고 해당 파일 이름의 모든 항목을 나열하는 방법

디렉터리에 많은 파일이 있고(Java 애플리케이션의 로그 - 한 줄에 하나의 레코드) 검색 문자열이 포함된 모든 파일 이름을 나열하고 특정 파일에서 해당 문자열이 나타나는 모든 항목을 나열하고 싶습니다.

나는 지금까지 이것을 사용해 왔습니다. 여기서는 파일 이름을 얻었고 아래에서는 일치하는 줄을 얻었지만 파일 이름 일치 줄이 어떤 파일 이름에서 나온 것인지 알 수 없습니다.

#!/bin/bash
cd ${DIRECTORY}
clear
echo 'WARNINGS'
egrep -l "WARN" * | sort
echo ''
cat * | grep 'WARN'

모든 파일 이름(WARN을 포함하는 이름만)을 나열하고 일치하는 모든 파일에 대해 특정 파일에 WARN 문자열이 있는 모든 줄을 표시해야 합니다.

답변1

잘 알려지지 않은 사실은 grep여러 파일을 검색할 때 (성공적으로) 검색한 파일의 이름을 인쇄할 수 있다는 것입니다. 즉, /dev/null검색할 파일 목록에 이를 포함하면 원하는 결과를 얻을 수 있습니다.

$ grep "something" /path/to/file
something (and some other thing)

하지만:

$ grep "something" /dev/null /path/to/file
/path/to/file:something (and some other thing)

이를 사용하면 다음을 수행할 수 있습니다.

$ find /path/to/start [-name "<filename pattern>"] \
                       -exec grep '<searchstr>' /dev/null {} \;

그러면 다음과 같은 출력이 제공됩니다.

/path/to/start/file1:<searchstr> foo
/path/to/start/file1:<searchstr> bar
/path/to/start/subdir/file2:foo <searchstr> bar
/path/to/start/subdir/file3:bar <searchstr> foo
...

@ilkkachu가 정확하게 지적했듯이, 내가 준 명령은 한 번에 하나의 파일을 grep. 이 프로세스를 최적화하는 한 가지 방법은 다음과 같이 작성하는 것입니다.

$ find /path/to/start [-name "<filename pattern>"] \
                       -exec grep '<searchstr>' /dev/null {} +

여기서 find여러 파일 이름을 한 번에 grep에 전달하면 grep이 덜 자주 호출되므로 로드가 줄어듭니다. 하나의 파일만 검색될 /dev/null수도 있으므로 지정해야 합니다 .find

답변2

여러 파일을 에 제공하면 grep출력의 각 줄에 파일 이름이 추가됩니다. 게다가 이렇게 하면 피할 수 있어요고양이를 위한 고전적인 쓸모없는 용도. 이를 사용할 때 셸 변수 이름에 대문자를 사용하지 마십시오. 관례적으로 전역 환경 변수 이름은 대문자이므로 자체 셸 변수도 대문자로 사용하면 이름 지정 충돌과 오류가 발생할 수 있습니다. 마지막으로, egrep더 이상 사용되지 않으며 grep -E(여기에서는 필요하지 않음 grep -E), 내용을 실행하기 전에 해당 디렉토리로 이동할 필요가 없지만, 그렇게 하는 경우 작업을 수행하기 전에 제대로 작동하는지 확인해야 합니다 cd. cd필요한 작업을 수행하는 향상된 스크립트 버전은 다음과 같습니다.

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep 'WARN' "$1"/*

이제 대상 디렉터리 이름을 인수로 전달하여 스크립트를 실행할 수 있습니다.

your_script /path/to/target

예를 들어, /home/terdon/foo내 시스템의 지정된 디렉토리에서 이를 실행하면 다음이 제공됩니다.

WARNINGS found in files in directory "/home/terdon/foo":
/home/terdon/foo/file2:WARNING from file2
/home/terdon/foo/file4:WARNING from file4
/home/terdon/foo/file4:WARNING2 from file4
/home/terdon/foo/file5:WARNING from file5

경로는 표시하지 않고 파일 이름만 표시하려면할 수 있는옵션 cd(그러나 위에서 언급한 것처럼 실패하면 종료해야 합니다 cd):

#!/bin/sh

clear
if cd -- "$1"; then
  :
else
  echo "cd to '$1' failed!"
  exit 1
fi

printf 'WARNINGS found in files in directory "%s":\n' "$1"

grep 'WARN' *

또는 출력에서 ​​경로를 제거할 수 있습니다.

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep 'WARN' "$1"/* | sed 's|.*/||'

마지막으로, 대상 디렉터리에 파일이 하나만 있는 경우에도 이것이 작동하는지 확인하려면 GNU grep(Linux의 기본값)을 사용하는 경우 -Hgrep에 항상 파일 이름을 포함하도록 지시하는 플래그를 사용할 수 있습니다.

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep -H 'WARN' "$1"/* | sed 's|.*/||'

grep지원하지 않으면 다음을 사용 -H하십시오.바쿠닌의 속임수여기에는 다음이 포함됩니다 /dev/null.

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep 'WARN' "$1"/* /dev/null | sed 's|.*/||'

답변3

더 나은 사용ack당신의 저장소에 Java.

이렇게 하면 디렉토리나 유사한 디렉토리에서 검색하는 것이 방지되므로 .git더 좋고 빠릅니다.

grep이 상황보다 더 나은 옵션이 더 많이 있습니다 .

노력하다(재귀적으로):

ack WARN
ack -l WARN

관련 정보