찾기가있는 특정 서브 디렉토리를 제외한 모든 파일 삭제


11

a하위 폴더의 모든 파일을 제외하고 한동안 폴더에 액세스하지 않은 모든 파일을 재귀 적으로 삭제하고 싶습니다 b.

find a \( -name b -prune \) -o -type f -delete

그러나 오류 메시지가 나타납니다.

find : -delete 조치는 자동으로 -depth를 설정하지만 -prune은 -depth가 적용되면 아무 것도 수행하지 않습니다. 어쨌든 계속하려면 -depth 옵션을 명시 적으로 사용하십시오.

추가 -depth하면 모든 파일 b이 포함되어 발생 하지 않아야합니다 .

이 작업을 수행하는 안전한 방법을 아는 사람이 있습니까?


@ MichaelKjörling : extglob을 살펴 보았지만 a제외하고 모든 것을 어떻게 포함 a/b합니까?
forthrin

cd a && ls -d !(b/*)작동 하지 않습니까? (그것을하기 위해서가 rm -r아니라 ls -d.)
CVn

귀하의 제안은 하위 폴더를 삭제합니다. 폴더를 그대로 유지하고 싶습니다. 트리의 모든 파일 을 찾아 삭제하고 싶습니다 a(아래의 파일 제외 a/b).
forthrin

따라서 -rrm으로 건너 뛰십시오 . bash의 확장 된 globbing을 사용하여 묻는 것이 상당히 쉬운 것으로 보이며, globbing 결과로 수행하는 작업은 귀하에게 달려 있습니다.
CVn

@ MichaelKjörling 두 문제가 모호하게 닮은 해결책으로 인해 질문이 중복되는 것은 아닙니다. 두 문제 각각에 대한 대부분의 솔루션은 다른 문제를 해결하지 못합니다.
Gilles 'SO- 악마 그만

답변:


13

TL; DR : 가장 좋은 방법은 -exec rm대신에 사용하는 것입니다 -delete.

find a \( -name b -prune \) -o -type f -exec rm {} +

설명:

-delete함께 사용하려고 할 때 왜 불만 이 -prune있습니까?

짧은 답변 : 때문에 -delete의미 -depth-depth만드는 -prune효과.

우리는 긴 대답에 오기 전에 첫번째와없는 발견의 행동을 관찰 -depth:

$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2

단일 디렉토리에서의 순서에 대한 보장은 없습니다. 그러나 디렉토리가 내용보다 먼저 처리된다는 보장이 있습니다. 참고 foo/모든 전에 foo/*하고 foo/bar어떤 전에 foo/bar/*.

이것은로 되돌릴 수 있습니다 -depth.

$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/

이제는 모두 foo/*앞에 나타납니다 foo/. 와 동일합니다 foo/bar.

더 긴 답변 :

  • -prune찾기가 디렉토리로 내려 가지 않도록합니다. 다시 말해 -prune디렉토리의 내용을 건너 뜁니다. 귀하의 경우 -name b -prune찾기가 이름이있는 디렉토리로 내려 가지 않습니다 b.
  • -depth디렉토리 자체보다 먼저 디렉토리의 내용을 처리합니다. 이는 find가 디렉토리 항목을 처리 할 때까지 b해당 내용이 이미 처리되었음을 의미합니다. 따라서 사실상 효과 -prune가 없습니다 -depth.
  • -delete의미 -depth는 다음 빈 디렉토리를 먼저 파일을 삭제 할 수 있습니다. -delete비어 있지 않은 디렉토리를 삭제하지 않습니다. -delete비어 있지 않은 디렉토리 를 강제 로 삭제하거나 -delete암시 하지 않도록 옵션을 추가하는 것이 가능할 것 -depth입니다. 그러나 그것은 또 다른 이야기입니다.

원하는 것을 달성하는 다른 방법이 있습니다.

find a -not -path "*/b*" -type f -delete

기억하기 쉬울 수도 있고 아닐 수도 있습니다.

이 명령은 여전히 ​​디렉토리로 내려 가서 거부 할 수 b있도록 모든 단일 파일을 처리 -not합니다. 디렉토리 b가 큰 경우 성능 문제 일 수 있습니다 .

-path와 다르게 작동합니다 -name. 전체 경로와 일치하는 -name동안 파일 또는 디렉토리의 이름과 만 일치 -path합니다. 예를 들어 경로를 관찰하십시오 /home/lesmana/foo/bar. -name -bar이름이이므로 일치합니다 bar. -path "*/foo*"문자열 /foo이 경로에 있기 때문에 일치 합니다. -path사용하기 전에 이해해야 할 몇 가지 복잡한 사항이 있습니다 find자세한 내용 은 맨 페이지 를 참조하십시오.

이것이 100 % 완전하지 않다는 것을 명심하십시오. "거짓 긍정적"일 가능성이 있습니다. 명령이 위에 작성되는 방식은 이름이 시작하는 상위 디렉토리가있는 파일 b(긍정) 을 건너 뜁니다 . 그러나 b트리의 위치에 관계없이 이름이 시작하는 파일은 건너 뜁니다 (거짓 긍정적). 보다 나은 표현을 작성하면 문제를 해결할 수 있습니다 "*/b*". 그것은 독자를위한 연습으로 남아 있습니다.

난 당신이 사용한다고 가정 a하고 b더 같은 자리 표시와 실제 이름은로 allosaurusbrachiosaurus. 당신이 넣으면 brachiosaurus대신에 b다음 오탐 (false positive)의 양이 크게 감소합니다.

적어도 오탐 (false positive)이 될 것입니다 하지 가 비극적으로하지 수 있도록, 삭제. 또한, 먼저 명령을 실행하지 않고 오 탐지 여부를 확인 -delete하고 (암시 적을 배치해야 함 -depth) 출력을 검사 할 수 있습니다.

find a -not -path "*/b*" -type f -depth

-not -path단지 일이었다! 관대 한 설명 감사합니다!
forthrin

1
-not -path작동 하는가에 대한 일부 설명은 -prune도움이되지 않습니다. 왜 -not -path공존 할 수 -depth있습니까?
Faheem Mitha

3

rm대신에 사용하십시오 -delete:

find a -name b -prune -o -type f -exec rm -f {} +

1
rm효과가 있고 효과 delete가 없는지 자세히 설명해 주 시겠습니까?
Faheem Mitha

1
@lesmana는 "-delete가 비어 있지 않은 디렉토리를 삭제하는 것을 거부하기 때문"이라고 생각합니다. 따라서 비어 있지 않은 디렉토리는 삭제하지 않습니다. 그러나 rm그 문제는 없습니다. 그러나 아무리 정교해도 좋은 것이 될 것입니다.
Faheem Mitha

@FaheemMitha, 그 대답은 질문에 있습니다. -delete암시 적으로 -depth작동하지 않습니다 -prune. -path작동하지만 find탐색 할 필요가없는 디렉토리에서 내림차순 멈추지 않습니다.
Stéphane Chazelas

0

위의 답변과 설명은 매우 도움이되었습니다.

"-exec rm {} +"또는 "-not -path ... -delete"의 해결 방법을 사용하지만 "find ... -delete"보다 속도가 훨씬 느릴 수 있습니다. -delete "는 NFS 파일 시스템의 깊은 디렉토리에서"-exec rm {} + "보다 5 배 빠르게 실행됩니다.

'-not path'솔루션은 제외 된 디렉토리와 그 아래의 모든 파일을 보는 명백한 오버 헤드를 가지고 있습니다.

"find .. -exec rm {} +"는 시스템 호출을 수행하는 rm을 호출합니다.

fstatat(AT_FDCWD, path...); 
unlinkat(AT_FDCWD, path, 0)

"find -delete"는 시스템 호출을 수행합니다.

 fd=open(dir,...);
 fchdir(fd); 
 fstatat(AT_FDCWD, filename,...)
 unlinkat(dirfd, filename,...)

따라서 "-exec rm {} +"rm 명령은 파일 당 두 번 inode 조회를위한 전체 경로를 수행하지만 "find -delete"는 현재 디렉토리에서 파일 이름의 통계 및 링크 해제를 수행합니다. 한 디렉토리에서 많은 파일을 제거 할 때 큰 승리입니다.

(와인 모드 켜짐 (죄송합니다))

-depth, -delete 및 -prune 사이의 상호 작용을 설계하면 "-prune 디렉토리에있는 파일을 제외한 파일 삭제"라는 일반적인 작업을 수행하는 가장 효율적인 방법을 불필요하게 제거하는 것처럼 보입니다.

"-type f -delete"조합은 디렉토리를 삭제하지 않기 때문에 -depth없이 실행할 수 있어야합니다. 또는 "find"에 디렉토리를 삭제하지 않는 "-deletefile"조치가 있으면 -depth를 암시 할 필요가 없습니다.

rm이 파일 이름을 정렬하고 디렉토리를 열고 전체 경로를 연결 해제하는 대신 unlinkat (dir_fd, filename)을 수행 할 수있는 옵션이있는 경우 xargs 또는 find -exec rm 명령 호출이 가속화 될 수 있습니다. -r 옵션으로 디렉토리를 반복 할 때 이미 unlinkat (dir_fd, filename)을 수행합니다.

(와인 모드 해제)

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