
다음과 같은 문제가 있습니다. 디렉토리 구조가 있고 이름이 지정된 디렉토리 내에 있는 모든 항목을 삭제하고 싶습니다 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/Caches
find
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