X일보다 오래된 파일만 포함된 디렉토리를 찾는 방법은 무엇입니까?

X일보다 오래된 파일만 포함된 디렉토리를 찾는 방법은 무엇입니까?

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-maxdepthprintf

이 특정 예에서는 (일) 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'를 추가하여 awkNUL로 구분하여 인쇄한 다음 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내장 기능을 사용하면 현재 작업 디렉토리를 수락하고 지울 수 있습니다.zshzmodload zsh/filesrm -rf ./

관련 정보