찾기 명령을 사용하지만 두 디렉토리의 파일 제외


88

로 끝나는 파일을 찾고 싶지만 및 폴더 _peaks.bed에있는 파일은 제외합니다 .tmpscripts

내 명령은 다음과 같습니다.

 find . -type f \( -name "*_peaks.bed" ! -name "*tmp*" ! -name "*scripts*" \)

하지만 작동하지 않았습니다. tmpscript폴더 의 파일 은 계속 표시됩니다.

누구든지 이것에 대한 아이디어가 있습니까?

답변:


191

다음과 find같이 지정하는 방법은 다음과 같습니다.

find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"

설명:

  • find . -현재 작업 디렉토리에서 찾기 시작 (기본적으로 재귀 적으로)
  • -type f- find결과에 파일 만 표시 하도록 지정
  • -name "*_peaks.bed" -이름으로 끝나는 파일을 찾습니다. _peaks.bed
  • ! -path "./tmp/*" -경로가 다음으로 시작하는 모든 결과 제외 ./tmp/
  • ! -path "./scripts/*" -경로가 다음으로 시작하는 모든 결과를 제외합니다. ./scripts/

솔루션 테스트 :

$ mkdir a b c d e
$ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
$ find . -type f ! -path "./a/*" ! -path "./b/*"

./d/4
./c/3
./e/a
./e/b
./e/5

당신은 꽤 가까웠습니다.이 -name옵션 -path은 전체 경로를 고려하는 기본 이름 만 고려합니다 =)


잘 하셨어요. 그러나 OP가 원하는 것 중 하나를 잊어 버렸습니다 _peaks.bed.
알렉스

2
이것은 GNU에서 많은 확장을 사용 find하지만 질문에 Linux 태그가 지정되어 있으므로 문제가되지 않습니다. 좋은 대답입니다.
Jonathan Leffler 2013 년

1
참고 : .초기 찾기 프롬프트에서 사용하는 경우 제외하는 각 경로에서 사용해야합니다. 경로 일치는 매우 엄격하며 퍼지 검색을 수행하지 않습니다. 따라서 사용 find / -type f -name *.bed" ! -path "./tmp/"하면 작동하지 않습니다. 당신 ! -path "/tmp"은 그것을 행복하게 만들어야합니다.
peelman 2013

3
*는 중요합니다. $ ! -path "./directory/*"
Thomas Bennett

3
man 페이지에 따르면 : "전체 디렉토리 트리를 무시하려면 트리의 -prune모든 파일을 확인 하는 대신 사용 하십시오." 제외 된 디렉토리가 매우 깊게 실행되거나 많은 파일이 있고 성능에 관심이 있다면 -prune대신 옵션 을 사용하십시오 .
thdoan

8

할 수있는 한 가지 방법이 있습니다 ...

find . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"

2
이것은 findGNU에서만이 아니라 모든 버전에서 작업 할 수있는 장점이 있습니다 find. 그러나 문제는 Linux로 태그되어 있으므로 중요하지 않습니다.
Jonathan Leffler 2013 년

2

사용하다

find \( -path "./tmp" -o -path "./scripts" \) -prune -o  -name "*_peaks.bed" -print

또는

find \( -path "./tmp" -o -path "./scripts" \) -prune -false -o  -name "*_peaks.bed"

또는

find \( -path "./tmp" -path "./scripts" \) ! -prune -o  -name "*_peaks.bed"

순서가 중요합니다. 왼쪽에서 오른쪽으로 평가됩니다. 항상 경로 제외로 시작하십시오.

설명

전체 디렉토리를 제외하기 위해 -not(또는 !)을 사용하지 마십시오 . 사용 -prune. 설명서에 설명 된대로 :

−prune    The primary shall always evaluate as  true;  it
          shall  cause  find  not  to descend the current
          pathname if it is a directory.  If  the  −depth
          primary  is specified, the −prune primary shall
          have no effect.

그리고 GNU에서 매뉴얼 찾기 :

-path pattern
              [...]
              To ignore  a  whole
              directory  tree,  use  -prune rather than checking
              every file in the tree.

실제로를 사용 -not -path "./pathname"하면 find는 아래의 각 노드에 대한 표현식을 평가합니다 "./pathname".

찾기 표현식은 조건 평가 일뿐입니다.

  • \( \)-그룹 작업 (을 사용할 수 -path "./tmp" -prune -o -path "./scripts" -prune -o있지만 더 자세합니다).
  • -path "./script" -prune-true를 -path반환하고 디렉토리이면 해당 디렉토리에 대해 true를 반환하고 그 디렉토리 로 내려 가지 마십시오 .
  • -path "./script" ! -prune- (-path "./script") AND (! -prune). prune의 "항상 참"을 항상 거짓으로 되돌립니다. "./script"일치로 인쇄하지 않습니다 .
  • -path "./script" -prune -false- -prune항상 true를 반환 -false하기 때문에 !.
  • -o-OR 연산자. 두 표현식 사이에 연산자가 지정되지 않은 경우 기본값은 AND 연산자입니다.

따라서 다음 \( -path "./tmp" -o -path "./scripts" \) -prune -o -name "*_peaks.bed" -print으로 확장됩니다.

[ (-path "./tmp" OR -path "./script") AND -prune ] OR ( -name "*_peaks.bed" AND print )

인쇄가 없으면 다음으로 확장되기 때문에 여기서 중요합니다.

{ [ (-path "./tmp" OR -path "./script" )  AND -prune ]  OR (-name "*_peaks.bed" ) } AND print

-print찾기에 의해 추가됩니다. 그렇기 때문에 대부분의 경우 표현식에 추가 할 필요가 없습니다. 그리고 -prunetrue를 반환 하므로 "./script"및 "./tmp"가 인쇄됩니다.

-prune항상 false를 반환하도록 전환했기 때문에 다른 것에서는 필요하지 않습니다 .

힌트 :를 사용 find -D opt expr 2>&1 1>/dev/null하여 최적화 및 확장 방법
find -D search expr 2>&1 1>/dev/null을 확인하고 어떤 경로가 확인되었는지 확인할 수 있습니다.


0

같은 것을 시도하십시오

find . \( -type f -name \*_peaks.bed -print \) -or \( -type d -and \( -name tmp -or -name scripts \) -and -prune \)

그리고 내가 그것을 조금 잘못 이해하더라도 너무 놀라지 마십시오. 목표가 exec (인쇄 대신) 인 경우에는 대신 대체하십시오.


0

나를 위해이 솔루션은 find 명령 exec에서 작동하지 않았으므로 이유를 모르겠습니다. 그래서 내 솔루션은

find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

설명 : sampson-chen과 동일하며

-prune-진행 경로 무시 ​​...

-o-일치하지 않으면 결과를 인쇄합니다 (디렉토리를 정리하고 나머지 결과를 인쇄).

18:12 $ mkdir a b c d e
18:13 $ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
18:13 $ find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

gzip: . is a directory -- ignored
gzip: ./a is a directory -- ignored
gzip: ./b is a directory -- ignored
gzip: ./c is a directory -- ignored
./c/3:    0.0% -- replaced with ./c/3.gz
gzip: ./d is a directory -- ignored
./d/4:    0.0% -- replaced with ./d/4.gz
gzip: ./e is a directory -- ignored
./e/5:    0.0% -- replaced with ./e/5.gz
./e/a:    0.0% -- replaced with ./e/a.gz
./e/b:    0.0% -- replaced with ./e/b.gz

수락 된 답변은 작동하지 않았지만 작동합니다. 가지 치기를 사용하여 find . -path ./scripts -prune -name '*_peaks.bed' -type f. 여러 디렉터리를 제외하는 방법을 잘 모르겠습니다. type지정된 경우에도 최상위 제외 디렉토리도 나열 됩니다. prune을 사용하여 찾기 작업의 속도를 높이고 싶지 않으면 Grep을 통해 제외하는 것이 더 간단 해 보입니다.
Mohnish

여러 디렉터리를 제외하는데도 문제가 있었지만 위의 설명은 효과가있는 대답을주었습니다. '-not -path'의 여러 인스턴스를 사용하고 각 경로 표현식에 첫 번째 매개 변수에 사용 된 전체 접두사를 포함하여 '찾기'를하고 각 항목을 별표로 끝냅니다 (그리고 모든 점은 이스케이프 처리).
jetset 2019

0

아래에서 시도해 볼 수 있습니다.

find ./ ! \( -path ./tmp -prune \) ! \( -path ./scripts -prune \) -type f -name '*_peaks.bed'

2
그와 같은 오래된 질문 (4 년!)에 대해 단순히 "덤프"코드가 아닌이 새로운 답변이 더 낫거나 다른 이유를 설명하고 싶습니다.
Nic3500
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.