sh에서 'find'의 '-prune'옵션을 사용하는 방법은 무엇입니까?


219

나는에서 주어진 예를 이해하지 못합니다. man find누구든지 나에게 몇 가지 예와 설명을 줄 수 있습니까? 정규 표현식을 결합 할 수 있습니까?


더 자세한 질문은 다음과 같습니다.

changeall와 같은 인터페이스를 가진 쉘 스크립트를 작성하십시오 changeall [-r|-R] "string1" "string2". 그것은의 접미사로 모든 파일을 찾을 것입니다 .h, .C, .cc, 또는 .cpp모든 항목 변경 string1에를 string2. -r현재 디렉토리에만 머 무르거나 하위 디렉토리를 포함하는 옵션입니다.

노트:

  1. 재귀 ls가 아닌 경우 허용되지 않으며 find및 만 사용할 수 있습니다 sed.
  2. 시도 find -depth했지만 지원되지 않았습니다. 그렇기 때문에 -prune도움이 될지 궁금 했지만의 예를 이해하지 못했습니다 man find.

EDIT2 : 과제를하고 있었는데 직접 끝내고 싶기 때문에 자세한 질문을하지 않았습니다. 나는 이미 그것을하고 나눠 주었으므로 이제 모든 질문을 진술 할 수 있습니다. 또한을 사용하지 않고 과제를 완료 -prune했지만 어쨌든 배우고 싶습니다.

답변:


438

내가 혼란스럽게 한 것은 테스트 (와 같은 )가 아니라 -prune행동 -print과 같은 것 -name입니다. "할 일"목록을 변경 하지만 항상 true를 반환합니다 .

사용하는 일반적인 패턴 -prune은 다음과 같습니다.

find [path] [conditions to prune] -prune -o \
            [your usual conditions] [actions to perform]

테스트의 첫 부분 (및 최대 포함 )은 실제로 원하는 항목 (예 : 정리 하지 않으려 는 항목)에 대해 false 를 반환 하므로 거의 항상 -o(논리적 OR)을 원합니다 .-prune-prune

예를 들면 다음과 같습니다.

find . -name .snapshot -prune -o -name '*.foo' -print

".snapshot"디렉토리에없는 "* .foo"파일을 찾을 수 있습니다. 이 예에서, -name .snapshot최대하게 [conditions to prune]하고 -name '*.foo' -print있다 [your usual conditions][actions to perform].

중요 사항 :

  1. 원하는 결과를 인쇄하기 만하면 작업을 수행하지 않아도됩니다 -print. 을 사용할 때 일반적으로 그렇게 하고 싶지 않습니다-prune .

    find의 기본 동작은 끝에 아이러니 한 동작 이외의 동작이없는 경우 동작 과 함께 전체 식 을 "및" -print수행하는 것 -prune입니다. 이것은 이것을 쓰는 것을 의미합니다 :

    find . -name .snapshot -prune -o -name '*.foo'              # DON'T DO THIS

    이것을 쓰는 것과 같습니다.

    find . \( -name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS

    즉, 정리하려는 디렉토리의 이름도 인쇄한다는 것을 의미합니다. 일반적으로 원하는 이름이 아닙니다. 대신 -print원하는 작업 을 명시 적으로 지정하는 것이 좋습니다.

    find . -name .snapshot -prune -o -name '*.foo' -print       # DO THIS
  2. "정상 조건"이 정리 조건과 일치하는 파일과 일치하는 경우 해당 파일이 출력에 포함 되지 않습니다 . 이 문제를 해결하는 방법은 -type d프룬 조건에 술어를 추가하는 것 입니다.

    예를 들어, 우리가 시작한 디렉토리를 제거하려고한다고 가정하고 .git(이것은 다소 다소 고안된 것입니다-일반적으로 정확히 이름을 가진 것만 제거하면 됩니다.git ), 이외의 파일을 포함하여 모든 파일을 보려고했습니다 .gitignore. 이것을 시도 할 수 있습니다 :

    find . -name '.git*' -prune -o -type f -print               # DON'T DO THIS

    이것은 출력에 포함 되지 않습니다.gitignore . 고정 버전은 다음과 같습니다.

    find . -name '.git*' -type d -prune -o -type f -print       # DO THIS

추가 팁 : GNU 버전 find의을 사용하는 경우 texinfo 페이지에 대한 find맨 페이지보다 자세한 설명이 있습니다 (대부분의 GNU 유틸리티에 해당됨).


6
텍스트에서 100 % 명확하지는 않지만 ( '* .foo'만 인쇄하므로 충돌하지 않음) -prune 부분은 ".snapshot"이라는 이름의 디렉토리 (인쇄뿐만 아니라)도 인쇄하지 않습니다. 즉, -prune디렉토리에서만 작동하지는 않습니다 (그러나 디렉토리의 경우 해당 조건과 일치하는 디렉토리 (예 : 디렉토리와 일치하는 디렉토리)를 입력하지 못함 -name .snapshot).
Olivier Dulac

12
잘 설명 된 설명 (특히 중요한 메모)에 대해 +1합니다. 당신은 이것을 찾기 개발자에게 제출해야합니다 (man 페이지는 정상적인 인간을위한 "다듬기"를 설명하지 않기 때문에 ^^ 그것을 알아 내려는 많은 시도가 필요했고, 부작용에 대해 경고하지 않았습니다)
Olivier Dulac

2
@OlivierDulac 그것은 당신이 유지하고 싶은 파일을 스트리핑하는 것에 대한 아주 좋은 지적입니다. 이것을 명확히하기 위해 답변을 업데이트했습니다. 그건 -prune그렇고 실제로 그 자체 가 아닙니다 . 문제는 또는 연산자가 "단락"하고 또는보다 우선 순위가 낮다는 것입니다. 최종 결과는라는 파일이있는 경우이다 .snapshot발생이 처음으로 일치합니다 -name, -prune다음, 아무것도하지 않을 것이다 (그러나 true를 반환), 그 왼쪽 인수는 사실 때문에 다음 또는 true를 반환합니다. 액션 (예 :) -print은 두 번째 인수의 일부이므로 실행할 기회가 없습니다.
Laurence Gonsalves 2012 년

3
+1은 결국 내가 왜 필요한지 알게되었습니다. -print이제 \! -path <pattern>추가 할 수 없습니다.-prune
Miserable Variable

6
"-o"는 "-or"의 약자이며 POSIX 호환은 아니지만보다 명확하게 읽습니다.
yoyo

27

일반적으로 리눅스에서 일을하는 기본 방식과 생각은 왼쪽에서 오른쪽입니다.
따라서 먼저 찾고있는 것을 작성하십시오.

find / -name "*.php"

그런 다음 enter 키를 누르고 원하지 않는 디렉토리에서 너무 많은 파일을 가져오고 있음을 알 수 있습니다. 마운트 된 드라이브를 검색하지 않도록 / media를 제외 시키십시오.
이제 이전 명령에 다음을 추가하면됩니다.

-print -o -path '/media' -prune

최종 명령은 다음과 같습니다.

find / -name "*.php" -print -o -path '/media' -prune

............... | <--- 포함 ---> | .................... | <- -------- 제외 ---------> |

나는이 구조가 훨씬 쉽고 올바른 접근 방식과 관련이 있다고 생각합니다.


3
나는이 효율적인 것으로 예상 않았을 것이다 - 나는 그것이 자두 전에 먼저 왼쪽 절을 평가하는 것이라고 생각했을 것이다, 그러나 놀랍게도 빠른 테스트는 제안 보인다 find공정에 영리 충분하다 -prune첫 번째 절을. 흠, 흥미로운.
artfulrobot

나는 거의 10 년 동안 GNU find를 사용한다고 생각한 적이 없다! 감사합니다! -prune지금부터 내가 생각하는 방식을 확실히 바꿀 것 입니다.
Felipe Alvarez

3
@artfulrobot 실제로 처리 하는가? 나는 /media그것이 호출되지 않았 음을 인식하고 *.php현재 내부에 있는지 여부를 확인하고 그것이 있는지 확인 /media하여 전체 하위 트리를 건너 뛰고 있다고 생각했을 것입니다. 여전히 왼쪽에서 오른쪽이며 두 검사가 겹치지 않는 한 차이가 없습니다.
phk

26

일부가 말했듯 이 -prune은 어떤 디렉토리 로 내려가는 것을 막지 않습니다 . 적용된 테스트와 일치하는 디렉토리로 내려 가지 않습니다. 아마도 일부 예제가 도움이 될 것입니다 (정규 예제의 맨 아래 참조). 너무 길어서 죄송합니다.

$ find . -printf "%y %p\n"    # print the file type the first time FYI
d .
f ./test
d ./dir1
d ./dir1/test
f ./dir1/test/file
f ./dir1/test/test
d ./dir1/scripts
f ./dir1/scripts/myscript.pl
f ./dir1/scripts/myscript.sh
f ./dir1/scripts/myscript.py
d ./dir2
d ./dir2/test
f ./dir2/test/file
f ./dir2/test/myscript.pl
f ./dir2/test/myscript.sh

$ find . -name test
./test
./dir1/test
./dir1/test/test
./dir2/test

$ find . -prune
.

$ find . -name test -prune
./test
./dir1/test
./dir2/test

$ find . -name test -prune -o -print
.
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

$ find . -regex ".*/my.*p.$"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test/myscript.pl

$ find . -name test -prune -regex ".*/my.*p.$"
(no results)

$ find . -name test -prune -o -regex ".*/my.*p.$"
./test
./dir1/test
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test

$ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py

$ find . -not -regex ".*test.*"                   .
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

또한 "touch ./dir1/scripts/test"를 터치하면 (즉, 출력 된 하위 디렉토리에 dir이 아닌 "test"파일 이있는 경우) find . -name test -prune -o -print: iow에 의해 인쇄되지 않습니다 . -prune파일 작업
Olivier Dulac

10

다른 답변에 제공된 조언에 추가 (응답을 작성할 담당자가 없습니다) ...

-prune다른 표현식과 결합 할 때 사용되는 다른 표현식에 따라 동작에 미묘한 차이가 있습니다.

@Laurence Gonsalves의 예는 ".snapshot"디렉토리에없는 "* .foo"파일을 찾습니다.

find . -name .snapshot -prune -o -name '*.foo' -print

그러나이 약간 다른 .snapshot속기 는 아마도 우연히 디렉토리 (및 중첩 된 .snapshot 디렉토리) 도 나열합니다 .

find . -name .snapshot -prune -o -name '*.foo'

그 이유는 (내 시스템의 맨 페이지에 따라) :-

주어진 표현식에 기본 -exec, -ls, -ok 또는 -print가 포함되어 있지 않으면 주어진 표현식은 다음과 같이 효과적으로 대체됩니다.

(given_expression)-인쇄

즉, 두 번째 예는 다음을 입력하여 용어 그룹을 수정하는 것과 같습니다.

find . \( -name .snapshot -prune -o -name '*.foo' \) -print

이것은 적어도 Solaris 5.10에서 나타났습니다. 약 10 년 동안 다양한 종류의 * nix를 사용한 후, 최근에 이런 일이 발생하는 이유를 검색했습니다.


사용 여부 -prune와 의 차이점에주의를 기울여 주셔서 감사합니다 -print!
mcw

3

정리는 디렉토리 스위치에서 되풀이되지 않습니다.

매뉴얼 페이지에서

-depth가 제공되지 않으면 true입니다. 파일이 디렉토리 인 경우, 그 디렉토리로 내려 가지 마십시오. -depth가 제공되면 false입니다. 효과가 없습니다.

기본적으로 하위 디렉토리로 보내지 않습니다.

이 예제를 보자 :

다음 디렉토리가 있습니다

  • / home / test2
  • / home / test2 / test2

당신이 실행하는 경우 find -name test2:

두 디렉토리를 모두 반환합니다

당신이 실행하는 경우 find -name test2 -prune:

/ home / test2 / test2를 찾기 위해 / home / test2로 내려 가지 않으므로 / home / test2 만 리턴합니다.


100 %가 아님 : "조건을 일치시킬 때 정리를 수행하고, 디렉토리 인 경우, 할 일 목록에서 제거하십시오 (예 : 입력하지 마십시오)". -prune은 파일에서도 작동합니다.
Olivier Dulac

2

나는 이것에 대해 전문가가 아닙니다 (이 페이지는 http://mywiki.wooledge.org/UsingFind 와 함께 매우 도움이되었습니다 )

방금 주목 한 -path것은 모든 기본 이름 과 일치하는 바로 다음find ( .이 예제에서는) 나오는 문자열 / 경로와 완전히 일치하는 경로입니다-name .

find . -path ./.git  -prune -o -name file  -print

현재 디렉토리에서 .git 디렉토리를 차단합니다 ( 에서 찾은 결과 . )

find . -name .git  -prune -o -name file  -print

모든 .git 하위 디렉토리를 재귀 적으로 차단합니다.

참고는 ./ 매우 중요합니다! -path고정 된 경로 . 또는 일치하지 않는 경로 가있는 경우 (또는 ' -o' 의 다른 쪽에서) 일치하지 않으면 찾기 직후에 오는 경로와 일치해야합니다 ! 나는 이것을 순진하게 알지 못했고 같은 기본 이름으로 모든 하위 디렉토리를 정리하지 않으려는 경우 -path를 사용하게했습니다.


주 당신의 일을 말은 경우에 find bla/당신은 필요 -path bla/.git (또는 당신이를 쑤셔 경우 *전면 대신 더 -name처럼 행동 것)
sabgenton

1

긴 지루한 내용이 아닌 dir 자체를 포함한 모든 것을 표시하십시오.

find . -print -name dir -prune

0

여기에 모든 좋은 답변을 읽으면 이제 다음 사항이 모두 동일한 결과를 반환한다는 것을 이해합니다.

find . -path ./dir1\*  -prune -o -print

find . -path ./dir1  -prune -o -print

find . -path ./dir1\*  -o -print
#look no prune at all!

그러나 마지막 것은 여전히 ​​dir1의 모든 것을 검색하기 때문에 훨씬 오래 걸립니다. 실제 질문은 -or실제로 검색하지 않고 원치 않는 결과를 얻는 방법 입니다.

따라서 자두는 과거 경기가 괜찮지 않지만 완료로 표시하는 것을 의미합니다.

http://www.gnu.org/software/findutils/manual/html_mono/find.html "그러나 이것은 '자르기'조치의 효과 때문이 아닙니다 (추가 하강 만 방지 할 수는 없습니다) ./src/emacs에 대해 "or"조건의 왼쪽이 성공했기 때문에이 효과는 '-o'를 사용하기 때문입니다. 이 특정 파일에 대한 핸드-사이드 ( '-print'). "


0

find파일 목록을 작성합니다. 제공 한 술어를 각각에 적용하고 통과 한 술어를 리턴합니다.

-prune결과에서 제외 를 의미하는 이 아이디어 는 실제로 혼란 스러웠습니다. 정리하지 않고 파일을 제외 할 수 있습니다.

find -name 'bad_guy' -o -name 'good_guy' -print  // good_guy

모든 -prune수행은 검색의 동작을 변경할 수 있습니다. 현재 일치하는 디렉토리 인 경우 "hey find, 방금 일치 한 파일을 내려받지 마십시오"라고 표시 됩니다. 검색 할 파일 목록에서 해당 트리 (파일 자체는 아님)를 제거합니다.

이름을 지정해야합니다 -dont-descend.


0

꽤 많은 답변이 있습니다. 그들 중 일부는 이론이 너무 무겁습니다. 나는 왜 자두가 필요한지 한 번 떠날 것이므로 아마도 첫 번째 / 예제 종류의 설명이 누군가에게 유용 할 것입니다 :)

문제

나는 약 20 개의 노드 디렉토리가있는 폴더를 가지고 있었고 각 node_modules디렉토리에는 예상대로 디렉토리가 있습니다.

프로젝트에 들어가면 각각이 표시됩니다 ../node_modules/module. 그러나 당신은 그것이 어떻게되는지 알고 있습니다. 거의 모든 모듈에는 종속성이 있으므로보고있는 것이 더 비슷합니다.projectN/node_modules/moduleX/node_modules/moduleZ...

나는 의존성의 의존성을 가진 목록으로 익사하고 싶지 않았다 ...

-d n/을 알면 -depth n각 프로젝트에서 원하는 main / first node_modules 디렉토리가 다음과 같이 다른 깊이에 있었기 때문에 도움이되지 않았습니다.

Projects/MysuperProjectName/project/node_modules/...
Projects/Whatshisname/version3/project/node_modules/...
Projects/project/node_modules/...
Projects/MysuperProjectName/testProject/november2015Copy/project/node_modules/...
[...]

첫 번째로 끝나는 경로 목록을 첫 번째 node_modules로 얻고 다음 프로젝트로 이동하여 어떻게 동일합니까?

시작하다 -prune

을 추가 -prune해도 여전히 표준 재귀 검색이 가능합니다. 각각의 "경로"가 분석되고, 모든 발견은 뱉어지고 find좋은 챕처럼 파고 들어갑니다. 그러나 node_modules내가 원하지 않는 것을 더 파고 들었습니다 .

따라서, 차이는 이들 서로 다른 경로의가 있다는 것입니다 -prune것입니다 find그것은 당신의 항목을 발견했을 때 특정 길을 그 더 아래를 파고 중지 할 수 있습니다. 제 경우에는 node_modules폴더입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.