a
하위 폴더의 모든 파일을 제외하고 한동안 폴더에 액세스하지 않은 모든 파일을 재귀 적으로 삭제하고 싶습니다 b
.
find a \( -name b -prune \) -o -type f -delete
그러나 오류 메시지가 나타납니다.
find : -delete 조치는 자동으로 -depth를 설정하지만 -prune은 -depth가 적용되면 아무 것도 수행하지 않습니다. 어쨌든 계속하려면 -depth 옵션을 명시 적으로 사용하십시오.
추가 -depth
하면 모든 파일 b
이 포함되어 발생 하지 않아야합니다 .
이 작업을 수행하는 안전한 방법을 아는 사람이 있습니까?
답변
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
더 같은 자리 표시와 실제 이름은로 allosaurus
와 brachiosaurus
. 당신이 넣으면 brachiosaurus
대신에 b
다음 오탐 (false positive)의 양이 크게 감소합니다.
적어도 오탐 (false positive)이 될 것입니다 하지 가 비극적으로하지 수 있도록, 삭제. 또한, 먼저 명령을 실행하지 않고 오 탐지 여부를 확인 -delete
하고 (암시 적을 배치해야 함 -depth
) 출력을 검사 할 수 있습니다.
find a -not -path "*/b*" -type f -depth
답변
rm
대신에 사용하십시오 -delete
:
find a -name b -prune -o -type f -exec rm -f {} +
답변
위의 답변과 설명은 매우 도움이되었습니다.
“-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)을 수행합니다.
(와인 모드 해제)