나는 디렉토리 (예를 들어,이 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
과 명령을 find
ZANNA의 대답처럼 , (또한 참조이 할 수있는 매우 강력하고 다양한 기능, 휴대용 방법입니다 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 globstar
globstar shell 옵션을 다시 끕니다.
globstar와 사이에는 몇 가지 실질적인 차이점이 find
있습니다.
find
globstar보다 훨씬 더 다양합니다. globstar로 할 수있는 모든 것, find
명령으로도 할 수 있습니다. 나는 globstar를 좋아하고 때로는 더 편리하지만 globstar는 일반적인 대안 이 아닙니다 find
.
위의 방법은 이름이로 시작하는 디렉토리 내부를 찾지 않습니다 .
. 때로는 그러한 폴더를 되풀이하고 싶지 않지만 때로는 그렇게합니다.
일반적인 glob와 마찬가지로 쉘은 모든 일치하는 경로 목록을 작성 grep
하고 glob 자체 대신 명령 ( )에 인수로 전달합니다 . 호출 된 파일이 너무 많아서 file.txt
결과 명령이 시스템을 실행하기에 너무 길면 위의 방법이 실패합니다. 실제로 수천 개 이상의 파일이 필요하지만 그럴 수 있습니다.
사용하는 방법 find
에는 다음과 같은 이유로이 제한이 적용되지 않습니다.
-
Zanna의 방법 은
grep
잠재적으로 많은 경로 인수 로 명령을 작성하고 실행합니다 . 그러나 단일 경로에 나열 될 수있는 것보다 더 많은 파일이 발견되면+
-terminated-exec
조치는 일부 경로로 명령을 실행 한 다음 더 많은 경로로 다시 실행하는 식입니다. 의 경우grep
여러 파일에서 문자열을 보내고,이 올바른 동작을 생성합니다.여기에서 다루는 globstar 방법과 같이 경로 앞에 각각의 경로가있는 일치하는 모든 줄을 인쇄합니다.
-
sudodus의 길은
grep
각file.txt
발견 에 대해 별도로 실행 됩니다 . 파일이 많은 경우 다른 방법보다 속도가 느릴 수 있지만 작동합니다.이 방법은 파일을 찾고 경로를 인쇄 한 다음 일치하는 줄이 있으면 인쇄합니다. 이것은 내 방법, Zanna ‘s 및 muru ‘ 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
--include
find
이 답변의 접근 방식은 찾은 각 파일에 대해 별도로 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