나는 디렉토리 (예를 들어,이 abc/def/efg
많은 하위 디렉토리 (예를 들어, :로를) abc/def/efg/(1..300)
). 이러한 모든 하위 디렉토리에는 공통 파일 (예 :)이 file.txt
있습니다. file.txt
다른 파일을 제외 하고이 문자열 만 검색하고 싶습니다 . 어떻게해야합니까?
나는을 사용 grep -arin "pattern" *
했지만 많은 하위 디렉토리와 파일이 있으면 매우 느립니다.
나는 디렉토리 (예를 들어,이 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" '{}' +
-H
에 grep
오직 하나의 경로에 전달 될 때 경로가 여전히 (오히려 파일에서 바로 일치하는 라인보다) 인쇄되어, 경우에, 그래서.
구축 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 옵션을 다시 끕니다.
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' {} +
bash
이 작업을 수행 하려면 셸을 사용해야한다는 것을보다 명확하게 설명 할 수 있습니다 . 당신은 않는다 "는 globstar의 bash 쉘 옵션"에서 암시 적으로 그 말을하지만, 쉽게 너무 빨리 읽는 사람들이 놓칠 수 있습니다.
**
globs의를 핵심 비판은 정확 :의 프리젠 테이션 **
이 대답은 shopt 내부 인 배쉬와 함께, 떠들썩한 파티에 고유 한 용어 "globstar"인 (내가 생각하는) 배쉬와 tcsh 만 해당 나는 그 복잡성 때문에 원래 이것에 대해 글을 썼지 만 다소 혼란 스럽다는 것이 맞습니다. 이 답변에서 길게 논의하기보다는 무거운 리프팅을 수행하는 다른 (완전히 철저한) 게시물에 연결했습니다.
-e
경로에 적용되어서는 안된다, 그러나 이것은 쉽게 고정됩니다. 첫 번째 명령의 경우 생략하십시오 -e
. 두 번째로 find . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;
또는을 사용하십시오 find . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;
. 사용자는 때때로 (와 당신의 방법을 선호 -e
하나 개의 경로 인쇄 다른 사람에게 사용 고정) 일치하는 한 줄을 ; 찾은 파일 당 하나의 경로를 인쇄 한 다음 grep
결과를 출력합니다.
grep
그 자체로 는 당신이하고있는 일을하지 않습니다 . 다른 비판도 잘못되었습니다. grep -H
로 실행 -exec
하면 --color
(또는 GREP_COLOR
) 없이 색상이 표시되지 않습니다 . IEEE 1003.1-2008은의{}
확장을 보장하지는 ##### {}:
않지만 우분투에는 GNU find가 있습니다. 괜찮다 면 게시물을 수정하여 -e
버그 를 수정 하고 사용 사례를 명확히하고 삭제 취소 여부를 확인할 수 있습니다. (삭제 된 게시물을 보거나 편집 할 담당자가 있습니다.)
당신은 이것을 필요 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).
find?
파일 이름을 지정하기 위해 플래그로 실행하는 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" {} \;
find abc/def/efg -name "file.txt" -type f -exec echo -e "##### {}:" \; -exec grep -i "pattern" {} \;
cd abc/def/efg
'change directory'명령 을 제거 할 것입니다 :-)
-e
옵션을 echo
? 그러면 백 슬래시가 포함 된 파일 이름이 엉망이됩니다. 사용 (2) {}
으로 의 부분 인수를 사용할 수 있다고 보장 할 수는 없습니다. -exec echo "#####" {} \;
또는 말하는 것이 좋습니다 -exec printf "##### %s:\n" {} \;
. (3) 왜 그냥 사용하지 -print
나 -printf
? (4) 또한 고려하십시오 grep -H
.
find . -name "file.txt" -type f -exec echo -e "\0033[32m{}:\0033[0m" \; -exec grep -i "pattern" {} \;
2) 당신이 옳을 수도 있지만 지금까지 이것은 나를 위해 일하고 있습니다. 3) -print 및 -printf도 대안입니다. 4) 이것은 이미 주요 답변에 있습니다. -어쨌든, 당신은 당신의 자신의 답변에 오신 것을 환영합니다 :-)
-exec
통화 가 필요하지 않습니다 . 사용 grep -H
하면 일치하는 텍스트뿐만 아니라 파일 이름 (색상)이 인쇄됩니다.
질문의 조건을 문학적으로 받아 들일 수 있다면 직접 grep을 사용할 수 있다고 지적하십시오.
grep 'pattern' abc/def/efg/*/file.txt
또는
grep 'pattern' abc/def/efg/{1..300}/file.txt