디렉토리의 지정된 파일 이름에서만 패턴 / 텍스트를 재귀 적으로 검색 하시겠습니까? 들어,이 abc/def/efg많은 하위 디렉토리 (예를 들어, :로를)

나는 디렉토리 (예를 들어,이 abc/def/efg많은 하위 디렉토리 (예를 들어, :로를) abc/def/efg/(1..300)). 이러한 모든 하위 디렉토리에는 공통 파일 (예 :)이 file.txt있습니다. file.txt다른 파일을 제외 하고이 문자열 만 검색하고 싶습니다 . 어떻게해야합니까?

나는을 사용 grep -arin "pattern" *했지만 많은 하위 디렉토리와 파일이 있으면 매우 느립니다.



답변

상위 디렉토리에서 해당 파일 만 사용 find하고 실행할 수 있습니다 grep.

find . -type f -iname "file.txt" -exec grep -Hi "pattern" '{}' +

답변

globstar를 사용할 수도 있습니다.

구축 grep과 명령을 findZANNA의 대답처럼 , (또한 참조이 할 수있는 매우 강력하고 다양한 기능, 휴대용 방법입니다 sudodus의 답변을 ). 그리고 muru가 사용하는 훌륭한 방법 올렸습니다 grep--include옵션을 . 그러나 grep명령과 쉘만 사용하려면 다른 방법 이 있습니다 . 쉘 자체 가 필요한 재귀를 수행하도록 할 수 있습니다 .

shopt -s globstar   # you can skip this if you already have globstar turned on
grep -H 'pattern' **/file.txt

-H플래그 차종은 grep단 하나 일치하는 파일을 찾을 경우에도 파일 이름을 보여줍니다. 필요한 -a경우 -i, 및 -n플래그 (예제에서)도 전달할 수 있습니다 grep. 그러나이 방법을 사용 -r하거나 통과 -R할 때 통과하지 마십시오 . 그것은이다 이 포함 된 글로브 패턴 확장에 디렉토리를 재귀 **하지를grep .

이 지침은 Bash 셸에만 해당됩니다. Bash는 Ubuntu (및 대부분의 다른 GNU / Linux 운영 체제)의 기본 사용자 셸이므로 Ubuntu를 사용 중이고 셸이 무엇인지 모른다면 거의 Bash입니다. 널리 사용되는 쉘은 일반적으로 디렉토리 탐색 **글로브를 지원하지만 항상 같은 방식으로 작동하지는 않습니다. 자세한 정보 는 Unix.SE 에서 ls *, ls ** 및 ls ***의 결과에 대한 Stéphane Chazelas탁월한 답변 을 참조하십시오 .

작동 원리

globstar bash shell 옵션을 켜면 **디렉토리 구분 기호 ( /)가 포함 된 일치 경로가 만들어 집니다. 따라서 디렉토리 재귀 글로브입니다. 구체적으로 man bash설명 하면 다음과 같습니다.

globstar의 쉘 옵션이 활성화되고, * 경로명 확장 컨텍스트에 사용되는 두 개의 인접한 * 모든 파일과 0 개 이상의 디렉토리 및 하위 디렉토리를 일치 하나의 패턴으로 사용 s의. /가 오는 경우, 인접한 두 개의 *는 디렉토리 및 하위 디렉토리에만 일치합니다.

수정하거나 당신이 의도 한 것보다 훨씬 더 많은 파일을 삭제 명령을 실행할 수 있기 때문에 당신이 쓰는, 특히 당신은이 조심해야 **당신이 쓰는 의미 할 때 *. (이 명령에서는 파일을 변경하지 않는 것이 안전합니다.) shopt -u globstarglobstar shell 옵션을 다시 끕니다.

globstar와 사이에는 몇 가지 실질적인 차이점이 find있습니다.

findglobstar보다 훨씬 더 다양합니다. globstar로 할 수있는 모든 것, find명령으로도 할 수 있습니다. 나는 globstar를 좋아하고 때로는 더 편리하지만 globstar는 일반적인 대안 이 아닙니다 find.

위의 방법은 이름이로 시작하는 디렉토리 내부를 찾지 않습니다 .. 때로는 그러한 폴더를 되풀이하고 싶지 않지만 때로는 그렇게합니다.

일반적인 glob와 마찬가지로 쉘은 모든 일치하는 경로 목록을 작성 grep하고 glob 자체 대신 명령 ( )에 인수로 전달합니다 . 호출 된 파일이 너무 많아서 file.txt결과 명령이 시스템을 실행하기에 너무 길면 위의 방법이 실패합니다. 실제로 수천 개 이상의 파일이 필요하지만 그럴 수 있습니다.

사용하는 방법 find에는 다음과 같은 이유로이 제한이 적용되지 않습니다.

  • Zanna의 방법grep잠재적으로 많은 경로 인수 로 명령을 작성하고 실행합니다 . 그러나 단일 경로에 나열 될 수있는 것보다 더 많은 파일이 발견되면 +-terminated -exec조치는 일부 경로로 명령을 실행 한 다음 더 많은 경로로 다시 실행하는 식입니다. 의 경우 grep여러 파일에서 문자열을 보내고,이 올바른 동작을 생성합니다.

    여기에서 다루는 globstar 방법과 같이 경로 앞에 각각의 경로가있는 일치하는 모든 줄을 인쇄합니다.

  • sudodus의 길은grepfile.txt발견 에 대해 별도로 실행 됩니다 . 파일이 많은 경우 다른 방법보다 속도가 느릴 수 있지만 작동합니다.

    이 방법은 파일을 찾고 경로를 인쇄 한 다음 일치하는 줄이 있으면 인쇄합니다. 이것은 내 방법, Zanna ‘smuru ‘ s 에서 생성 한 형식과 다른 출력 형식입니다 .

와 함께 색상 얻기 find

globstar를 사용하면 즉각적인 이점 중 하나는 기본적으로 Ubuntu에서 grep색상이 지정된 출력물이 생성된다는 것입니다. 그러나 당신은 쉽게 이것을 얻을 수있는 find .

사용자는 우분투가 만들어집니다에 계정 별칭 하게 grep정말 실행 grep --color=auto(실행 alias grep참조). 그건 좋은 일이 별칭이되는 거의 유일한 대화 형을 발행 할 때 확장 ,하지만 당신이 원한다면 것을 의미 find호출 grep--color플래그, 당신은 명시 적으로 작성해야합니다. 예를 들면 다음과 같습니다.

find . -name file.txt -exec grep --color=auto -H 'pattern' {} +

답변

당신은 이것을 필요 find로 하지 않습니다 ; grep자체적으로 완벽하게 처리 할 수 ​​있습니다.

grep "pattern" . -airn --include="file.txt"

보낸 사람 man grep:

--exclude=GLOB
      Skip  files  whose  base  name  matches  GLOB  (using   wildcard
      matching).   A  file-name  glob  can  use  *,  ?,  and [...]  as
      wildcards, and \ to quote  a  wildcard  or  backslash  character
      literally.

--exclude-from=FILE
      Skip  files  whose  base name matches any of the file-name globs
      read from FILE  (using  wildcard  matching  as  described  under
      --exclude).

--exclude-dir=DIR
      Exclude  directories  matching  the  pattern  DIR from recursive
      searches.

--include=GLOB
      Search  only  files whose base name matches GLOB (using wildcard
      matching as described under --exclude).

답변

파일 이름을 지정하기 위해 플래그로 실행하는 muru의 답변에 제공된 방법 이 종종 최선의 선택입니다. 그러나이 작업을 수행 할 수도 있습니다 .grep--includefind

이 답변의 접근 방식은 찾은 각 파일에 대해 별도로 find실행 grep하고 각 파일에서 찾은 일치하는 줄 위에 각 파일의 경로를 정확히 한 번 인쇄 합니다. (모든 일치하는 줄 앞에 경로를 인쇄하는 방법은 다른 답변에서 다룹니다.)


디렉토리를 해당 파일이있는 디렉토리 트리의 맨 위로 변경할 수 있습니다. 그런 다음 다음을 실행하십시오.

find . -name "file.txt" -type f -exec echo "##### {}:" \; -exec grep -i "pattern" {} \;

그러면 .이름이 지정된 각 파일 의 경로 (현재 디렉토리를 기준으로하고 파일 이름 자체 포함)와 파일의 file.txt모든 일치하는 행이 인쇄됩니다. {}찾은 파일의 자리 표시 자 이므로 작동 합니다. 각 파일의 경로는 접두사가 붙음으로써 내용과 별도로 설정 #####되며 해당 파일의 일치하는 줄 앞에 한 번만 인쇄됩니다. file.txt일치하는 항목이없는 호출 된 파일 에는 여전히 경로가 인쇄되어 있습니다. 모든 일치하는 줄의 시작 부분에 경로를 인쇄하는 메소드에서 얻는 것보다이 출력이 어수선하지 않을 수 있습니다.

올바른 이름의 파일을 검색하고 다른 모든 파일을 건너 뛰기 때문에 find이와 같이 사용 하면 거의 항상 모든 파일 ( )에서 실행 grep하는 것보다 빠릅니다 .grep -arin "pattern" *find

우분투는 GNU 찾기를 사용 하는, 항상 확장 {}은 더 큰 문자열에 표시되는 경우에도 같은 ##### {}:. 이 기능을 지원하지 않는 시스템 에서 작업find 할 명령이 필요 하거나 -exec꼭 필요한 경우에만 작업 을 사용하려는 경우 다음을 사용할 수 있습니다.

find . -name "file.txt" -type f -printf '##### %p:\n' -exec grep -i "pattern" {} \;

출력을보다 쉽게 ​​읽을 수 있도록 ANSI 이스케이프 시퀀스를 사용하여 색상이 지정된 파일 이름을 얻을 수 있습니다. 이렇게하면 각 파일의 경로 머리글이 그 아래에 인쇄되는 일치하는 줄에서 더 잘 나타납니다.

find . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;

그러면 이 녹색 의 이스케이프 코드 를 터미널에서 녹색을 생성하는 실제 이스케이프 시퀀스로 바꾸고 일반 색상의 이스케이프 코드와 동일한 작업을 수행하게됩니다. 이 이스케이프는로 전달되어 find파일 이름을 인쇄 할 때 사용됩니다. ( 의 조치가 ANSI 이스케이프 코드 해석을 인식하지 못 $' '하므로 여기에 인용이 필요합니다 .)find-printf\e

원하는 경우 시스템 명령 (을 지원하는 ) -exec과 함께 사용할 수 있습니다 . 따라서 동일한 작업을 수행하는 다른 방법은 다음과 같습니다.printf\e

find . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;

답변

질문의 조건을 문학적으로 받아 들일 수 있다면 직접 grep을 사용할 수 있다고 지적하십시오.

grep 'pattern' abc/def/efg/*/file.txt

또는

grep 'pattern' abc/def/efg/{1..300}/file.txt