a
하위 폴더의 모든 파일을 제외하고 특정 기간 동안 폴더에 액세스하지 않은 모든 파일을 반복적으로 삭제하고 싶습니다 b
.
find a \( -name b -prune \) -o -type f -delete
그러나 오류 메시지가 나타납니다.
find: -delete 작업은 자동으로 -deep을 활성화하지만 -prune은 -deep이 적용되는 동안 아무 작업도 수행하지 않습니다. 계속하려면 -length 옵션을 명시적으로 사용하세요.
-depth
추가하면 모든 파일이 포함 됩니다 .b
아니요발생하다.
이를 수행하는 안전한 방법을 아는 사람이 있습니까?
답변1
한 가지 방법은 -exec rm
대신 사용하는 것입니다 -delete
.
find a \( -name b -prune \) -o -type f -exec rm {} +
또는 -not -path
대신 사용하십시오 -prune
:
find a -not -path "*/b*" -type f -delete
왜 -prune
다음과 충돌하는지 설명하세요 -delete
.
힌트를 주고 만들기 가 효과가 없기 때문에 with를 사용하려고 하면 -delete
불만 사항을 알게 될 것입니다 .-prune
-delete
-depth
-depth
-prune
다음을 사용하거나 사용하지 않고 find 동작을 관찰합니다 -depth
.
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
단일 디렉터리 내의 순서는 보장되지 않습니다. 그러나 디렉토리는 내용보다 먼저 처리됩니다. foo/
before foo/*
및 foo/bar
before 를 참고하세요 foo/bar/*
.
이것은 되돌릴 수 있습니다 -depth
.
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
현재가 foo/*
before보다 앞에 온다는 점에 유의하세요 foo/
. 와 동일합니다 foo/bar
.
추가 설명:
-prune
find가 디렉토리로 내려오는 것을 방지합니다. 즉,-prune
디렉터리의 내용을 건너뜁니다. 귀하의 경우-name b -prune
이는 find가 해당 이름의 디렉토리에 도달하면b
모든 하위 디렉토리를 포함하여 해당 디렉토리를 건너뛰는 것을 의미합니다.-depth
find가 디렉토리 자체보다 먼저 디렉토리의 내용을 처리하도록 합니다. 이는 find가 디렉토리 항목 처리를 시작할 때b
그 내용이 이미 처리되었음을 의미합니다. 따라서-prune
유효하지 않음과-depth
유효함.-delete
즉,-depth
콘텐츠를 먼저 삭제한 다음 빈 디렉터리를 삭제할 수 있습니다.-delete
비어 있지 않은 디렉토리 삭제를 거부합니다.
대체 방법 설명:
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
and를 b
자리 표시자로 사용하고 있고 실제 이름은 allosaurus
and에 더 가깝다고 가정합니다 brachiosaurus
. 이를 대체하면 오탐 brachiosaurus
( b
false positive) 수가 크게 줄어들 것입니다.
적어도 거짓 긍정은 다음과 같습니다.아니요너무 비참하지 않도록 삭제했습니다. 또한 먼저 명령 없이 명령을 실행하고 -delete
(암시적인 명령을 입력해야 함 -depth
) 출력을 검사하여 오탐지를 확인할 수 있습니다 .
find a -not -path "*/b*" -type f -depth
답변2
rm
대신 사용하십시오 -delete
:
find a -name b -prune -o -type f -exec rm -f {} +
답변3
위의 답변과 설명이 매우 도움이 됩니다.
나는 "-exec rm {} +" 또는 "-not -path ... -delete"와 같은 해결 방법을 사용하지만 "find ... -delete"보다 훨씬 느릴 수 있습니다. NFS 파일 시스템의 깊은 디렉토리에서 "find... -delete"가 "-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"는 현재 디렉터리의 파일 이름을 계산하고 연결을 해제합니다. 디렉터리에서 많은 수의 파일을 삭제할 때 이는 큰 이점입니다.
(와인 모드 켜짐(죄송합니다))
-length, -delete 및 -prune 사이의 상호 작용 설계는 "-prune 디렉터리에 있는 파일 이외의 파일 삭제"라는 일반적인 작업을 수행하는 가장 효율적인 방법을 불필요하게 제거한 것 같습니다.
"-type f -delete" 조합은 디렉토리 삭제를 시도하지 않으므로 -deep 없이 실행될 수 있어야 합니다. 또는 "find"에 "-deletefile" 작업이 있으면(디렉토리를 삭제하지 않음을 의미), -깊이를 암시할 필요가 없습니다.
rm에 파일 이름을 정렬하고, 디렉토리를 열고, 전체 경로 링크를 해제하는 대신 unlinkat(dir_fd,filename)을 수행하는 옵션이 있는 경우 rm 명령에 대한 xargs 또는 find -exec 호출 속도가 빨라질 수 있습니다. -r 옵션을 사용하여 디렉터리로 재귀할 때 unlinkat(dir_fd,filename)이 수행되었습니다.
(와인 모드 꺼짐)