find를 사용하여 특정 디렉토리를 찾고 한 디렉토리를 제외한 모든 파일을 삭제하십시오.

find를 사용하여 특정 디렉토리를 찾고 한 디렉토리를 제외한 모든 파일을 삭제하십시오.

다음과 같은 문제가 있습니다. 디렉토리 구조가 있고 이름이 지정된 디렉토리 내에 있는 모든 항목을 삭제하고 싶습니다 Caches. 이름이 지정된 모든 디렉터리를 제외하고 모두 삭제해야 합니다 Snapshots. 이걸 어떻게 해야 할지 모르겠어요찾다또는 내가 아는 다른 명령.

내가 묻는 이유: iOS의 모든 앱에는 자체 Caches 디렉터리가 있습니다. 앱에 따라 제대로 삭제되지 않는 경우도 있습니다. 이 답변에 대한 솔루션을 사용하면 iOS에서 캐시를 지울 수 있으므로 장치의 드라이브가 FUSE(iExplorer)와 같은 다른 컴퓨터에 마운트될 때 디스크 공간을 최적화할 수 있습니다.

이것이 내가 지금까지 가지고 있는 것입니다:

find . 2>/dev/null -type d -name "Caches" -maxdepth 3 -print

이는 다음과 같은 결과를 반환합니다:

./Library/Caches

이 작업을 수행하면 궁극적으로 이 항목을 제외한 모든 항목을 원하기 때문에 제외하고 싶은 ls ./Library/Caches모든 내용과 디렉토리가 표시됩니다 .Snapshots-delete


나는 다음과 같은 것을 원합니다 :

  Before:                            After:

  .                                  .
  ├── a                              ├── a
  │   ├── a                          │   ├── a
  │   └── Caches                     │   └── Caches
  │       ├── a                      │       └── a
  │       │   └── Snapshots          │           └── Snapshots
  │       │       └── a              │               └── a
  │       ├── b                      └── b
  │       │   └── a                      └── c
  │       └── c                  
  └── b
      ├── c
      └── Caches
          ├── a
          │   └── foo
          │       └── a
          └── b
              └── a

답변1

질문의 표현이 조금 혼란 스럽습니다. ./Library/Caches이라는 단일 폴더를 제외하고 디렉터리 의 모든 항목을 삭제하려는 경우 를 Snapshots사용할 필요가 없습니다 find. 에서 bash쉘 글로브는 가장 간단한 방법입니다:

shopt -s extglob  # probably already enabled
echo Library/Caches/!(Snapshots)

삭제하려는 모든 파일/디렉토리가 인쇄되면 echo로 바꾸십시오 rm -f --.

보존하려는 Snapshots디렉터리 트리의 여러 수준에 여러 개의 디렉터리가 있는 경우 GNU를 사용하면 다음 을 수행할 수 있습니다../Library/Cachesfind

find Library/Caches ! -path '*Snapshots*'

Snapshots 그러면 해당 경로에 있는 파일/디렉터리를 제외한 모든 파일/디렉터리가 인쇄됩니다 . 디렉터리를 포함하는(또는 그 하위 항목을 포함하는) Snapshots디렉터리를 포함하지만 find ... -delete해당 디렉터리를 삭제하지 않고 대신 비어 있지 않다는 오류를 인쇄합니다. 만족스러우면 -delete끝에 추가하세요.

한 가지 주의할 점은 이 경우파일이름 Snapshots그대로 그대로. 이것이 문제라면 대신 다음을 수행하십시오.

find Library/Caches \( ! -path '*Snapshots*' -o -type f -name Snapshots \)

-delete만족스러우면 다시 추가하세요 .

답변2

find . -depth -print0 | perl -0lne '
  if ("$_/" =~ m{/Caches(/.*)}s && $1 !~ m{/Snapshots/}) {rmdir $_ or unlink $_}'

find지원되지 않는 경우 -print0로 대체할 수 있습니다 -exec printf '%s\0' {} +.

아이디어는 NUL로 끝나는 파일 목록을 인쇄하고(0은 파일 경로에서 발생할 수 없는 유일한 바이트이므로) 을 perl옵션 -n과 함께 사용하여 -0해당 파일 이름 각각에 대해 일부 코드를 실행하는 것입니다( $_파일 이름으로 설정됨). ).

를 사용하면 -depth파일이 상위 디렉토리 앞에 인쇄됩니다. depth해당 경로에 /Caches/not 가 포함된 경우 파일이나 디렉토리만 제거합니다(비어 있다고 가정하므로 목록을 순서대로 처리하는 것이 중요합니다 ) /Snapshosts/.

답변3

저는 마법사가 아니기 find때문에 로 할 수 없다고 말하고 싶지는 않지만 find의 몇 줄로 할 수 있다는 것은 압니다 bash. 귀하의 디렉토리 구조를 올바르게 이해하고 있다고 가정하면 다음과 같습니다.

#!/bin/bash

for i in Library/Caches/*; do
    if [[ -d "$i" ]]; then
         [[ "$i" =~ "Snapshots" ]] ||  echo "rm-ing  $i" # change to rm -rf "$i" to use
    fi
done

for명령문은 의 각 항목을 반환합니다 Library/Caches/. 이 if [[ -d "$i" ]]명령문은 각 항목이 디렉토리인지 확인하고 디렉토리인 경우 이름을 검사하여 "스냅샷"이 포함되어 있는지 확인합니다 [[ "$i" =~ "Snapshots" ]]. 와 같이 정규식 일치를 무효화하는 연산자가 없기 때문에 이전 명령이 실패하는 경우(예: 디렉토리 이름에 스냅샷이 포함되지 않은 경우) 실행 !=~하곤 했습니다 .||rm

이는 를 사용하는 모든 최신 시스템에서 실행되지만 bash가 ​​있어야 합니다 bash. 또한 디렉토리 구조를 가지고 놀아야 할 수도 있지만 그렇게 하면 됩니다.

답변4

첫 번째 부분: 캐시라는 이름의 디렉토리를 찾아 해당 디렉토리로 작업 수행

find . -name Caches -type d -exec … \;

두 번째 부분: 캐시 디렉터리를 탐색하고 모든 것을 제거하지만 Snapshots하위 디렉터리와 해당 콘텐츠(및 해당 하위 디렉터리로 연결되는 경로)는 유지합니다. 디렉터리가 비면 삭제할 수 있도록 깊이 우선 순회를 수행합니다.

    find /path/to/Caches -depth -name Snapshots -type d -prune \
                             -o \( -type d -empty -o ! -type d \) -delete

이제 함께 결합하십시오.

find . -name Caches -type d -exec
    find {} -depth -name Snapshots -type d -prune \
                -o \( -type d -empty -o ! -type d \) -delete

관련 정보