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

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

다음과 같은 문제가 있습니다. 디렉터리 구조가 있고 디렉터리의 모든 항목을 삭제하고 싶습니다 Caches. 이름이 지정된 모든 디렉터리를 제외하고 모든 내용을 삭제해야 합니다 Snapshots. 나는 이것을하는 방법을 모른다찾다아니면 내가 아는 다른 명령이라도요.

제가 묻는 이유는 iOS에서 각 애플리케이션에 자체 Caches 디렉터리가 있기 때문입니다. 응용 프로그램에 따라 제대로 지워지지 않는 경우도 있습니다. 이 답변의 솔루션을 사용하면 FUSE(iExplorer)를 사용하는 등 장치의 드라이브가 다른 컴퓨터에 마운트될 때 iOS에서 캐시를 지워 디스크 공간을 최적화할 수 있습니다.

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

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이름이 지정된 단일 폴더를 제외하고 디렉토리의 모든 항목을 삭제하려는 경우 쉘 glob을 Snapshots사용할 필요가 없는 가장 쉬운 방법은 다음과 같습니다.findbash

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은 파일 경로에 나타날 수 없는 유일한 바이트이므로) 옵션 ( filename 으로 perl설정 )을 사용하여 각 파일 이름에 대해 일부 코드를 실행하는 것입니다.-n-0$_

를 사용하면 -depth파일이 상위 디렉터리 앞에 인쇄됩니다. 파일이나 디렉터리 depth의 경로 /Caches//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" ]]명령문은 각 항목이 디렉토리인지 확인하고, 그렇다면 이름에 "Snapshots" 가 포함되어 있는지 확인합니다 [[ "$i" =~ "Snapshots" ]]. 정규식 일치를 무효화하는 연산자가 없기 때문에 !=~이전 명령이 성공하지 못했을 때 (예: 디렉터리 이름에 스냅샷이 포함되지 않았을 때) ||이를 수행 했습니다.rm

이것은 사용되는 모든 최신 시스템에서 작동 bash하지만 반드시 작동해야 합니다 bash. 또한 디렉토리 구조를 가지고 놀아야 할 수도 있지만 이것이 효과가 있을 것입니다.

답변4

1부: 캐시라는 이름의 디렉터리를 찾아 몇 가지 작업 수행

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

2부: 캐시 디렉터리를 반복하고 모든 항목을 삭제하지만 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

관련 정보