X일이 지난 파일(생성/수정)만 포함된 디렉터리를 삭제해야 합니다.
이렇게 해봤는데 오늘 파일만 표시되고 재귀적으로 표시되지는 않습니다...
for d in *; do
find "$d" -mindepth 1 -mtime -180 -print -quit | | grep -q . ||
echo rm -rf "$d";
done
답변1
당신이 원해요"X일보다 오래된 파일만 포함된 디렉터리 삭제".
이를 처리하는 한 가지 방법은 다음과 같습니다.
- 리프 노드부터 시작하여 각 디렉터리에 대해 차례로 다음을 수행합니다.
- 하위 디렉터리 수를 계산합니다. 0이 아닌 경우 건너뜁니다.
- 디렉터리가 아닌 항목의 수를 계산합니다. 0이면 건너뜁니다.
- 기준(연령)과 일치하는 문서 수 계산
- 두 파일의 번호가 같으면 해당 디렉터리를 삭제하세요.
이 솔루션에는 GNU 또는 find
, 및 를 이해하는 대체 버전이 필요합니다.-mindepth
-maxdepth
printf
이 특정 예에서는 (일) X
로 설정됩니다 .180
days=180
find ./* -depth -type d -exec sh -c '
[ -z "'"$days"'" ] && exit 1
printf "Considering directory: %s\n" "$1"
dirs=$(find "$1" -mindepth 1 -maxdepth 1 -type d -print | xargs)
if [ -n "$dirs" ]
then
printf "Found child directories: (%s)\n" "$dirs"
exit 0
fi
all=$(find "$1" -maxdepth 1 ! -type d -printf x | wc -c)
got=$(find "$1" -maxdepth 1 -type f -mtime +'"$days"' -printf x | wc -c)
printf "Found %d item(s) and matched %d\n" $all $got
if [ $all -gt 0 ] && [ $all -eq $got ]
then
printf "Delete directory: %s\n" "$1"
: rm -rf "$1"
fi
' _ {} \;
변수의 두 가지 용도를 둘러싼 겉보기에 이상한 따옴표는 $days
스크립트의 나머지 부분이 작은 따옴표로 묶인 반면 변수는 큰 따옴표로 묶여 값이 결정될 수 있도록 하기 위한 것입니다. '..start of script..' "$variable" '..remainder of script..'
한 종류의 따옴표의 끝 부분과 다른 종류의 따옴표의 시작 부분 사이에 공백이 없다는 점을 이해하는 것이 더 쉬울 수도 있습니다 .
printf
코드를 자동으로 실행하려면 다음 문을 제거하세요. 삭제할 준비가 되면 :
앞의 콜론( )을 제거하세요.rm -rf
답변2
이는 해당 파일의./a/b
포함./a
최신 파일을180일보다 오래된 비디렉토리 파일을 포함하지 않는 가장 얕은 디렉터리가 존재한다고 가정할 때의 변형입니다(두./a
./a/b
파일이 없는 가장 얕은 디렉터리만 나열합니다., 그래서 당신은 사용할 수 있습니다내 대답GNU 시스템의 경우:
find . -type d -print0 -o -mtime -180 -printf 'f/%h\0' |
LC_ALL=C sort -zru |
LC_ALL=C awk -F/ -v RS='\0' '
function parent(path) {
sub("/[^/]*$", "", path)
return path
}
$1 == "f" {
sep = path = ""
for (i = 2; i <= NF; i++) {
black[path = path sep $i]
sep = FS
}
next
}
! ($0 in black) && ($0 == "." || parent($0) in black)'
목차를 검정색으로 칠하면 어떨까요?어느디렉터리가 아닌 파일은 해당 파일을 검은색으로 표시합니다.180일 이내에 디렉터리가 아닌 모든 파일.
또는 가장 가까운 파일이 발견되면 배열에서 디렉터리를 제거하는 변형입니다.
find . -type d -printf '%p/\0' -o -mtime -180 -printf '%h/f\0' |
LC_ALL=C sort -zu |
LC_ALL=C awk -F/ -v RS='\0' '
function parent(path) {
sub("[^/]+/?$", "", path)
return path
}
/\/$/ {dir[$0]; next}
{
path = ""
for (i = 1; i <= NF; i++)
delete dir[path = path $i FS]
}
END {
for (path in dir) if (! (parent(path) in dir)) print path
}'
(가장 얕은 것이 아니라) 둘 다 원하는 경우 더 간단해 ./a
집니다 ../a/b
find . -type d -printf '%p/\0' -o -mtime -180 -printf '%h/f\0' |
LC_ALL=C sort -zu |
LC_ALL=C awk -F/ -v RS='\0' '
/\/$/ {dir[$0]; next}
{
path = ""
for (i = 1; i <= NF; i++)
delete dir[path = path $i FS]
}
END {
for (path in dir) print path
}'
이를 제거하려면 to -v ORS='\0'
를 추가하여 awk
NUL로 구분하여 인쇄한 다음 to로 파이프하십시오 . 그러나 대부분의 구현에서는 반환된 경우(현재 디렉토리에 최근 파일이 없는 경우) 아무 작업도 거부한다는 xargs -r0 rm -rf
점에 유의하십시오 ../
rm
이러한 방법은 find
전체 디렉터리 트리를 한 번만 실행하고 탐색하기 때문에 가장 가까운 파일을 찾기 위해 각 디렉터리의 콘텐츠를 크롤링하는 간단한 방법보다 더 효율적입니다.
덜 효율적인 방법은 다음과 같습니다 zsh
.
print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/**/*(NDm-180Y1^/)'])
(포함되지 않았지만 다음을 사용하여 .
목록에 추가할 수 있습니다.{.,**/*}(...)
현재 디렉토리의 하위 디렉토리만 고려하려는 경우 이 접근 방식이 더 효율적이고(위의 방법이 Y1
첫 번째 일치에서 중지되므로) 더 짧고 간단해집니다.
print -rC1 -- *(ND/^e['()(($#)) $REPLY/**/*(NDm-180Y1^/)'])
.*
1을 해결 방법으로 사용합니다. 일부 셸에서는 확장에 .
및 가 포함되어 ..
에 재앙적인 결과를 초래할 수 있기 때문입니다 rm -rf .*
. 활성화된(결함이 없는 쉘) rm
내장 기능을 사용하면 현재 작업 디렉토리를 수락하고 지울 수 있습니다.zsh
zmodload zsh/files
rm -rf ./