한 줄에 다음을 수행하는 것이 가능합니까?
shopt -s extglob
rm -r !(folder1|file1|folder2)
rm -r folder2/!(subfolder)
rm -r folder2/subfolder/!(onefile)
예를 들면 이런 것?
rm -r !(folder1|file1|folder2/subfolder/onefile)
답변1
-path
도구의 (부정적) 테스트를 사용할 수 있습니다 find
. 도구가 지원하는 경우 -delete
비교적 간단합니다.
find . ! -path ./folder1 ! -path './folder1/*' ! -path ./file1 ! -path ./folder2/subfolder/onefile -delete
onefile
존재하는 경우 오류 가 보고 subfolder
됩니다 . 이렇게 하면 생존할 수 있지만 종료 상태는 유지되지 않습니다 .folder2
cannot delete: Directory not empty
find
0
find
지원하는 경우 -empty
디렉터리 이전에 디렉터리가 비어 있는지 테스트할 수 있습니다 -delete
. 일반적으로 말하면 디렉터리가 아닌 항목이 비어 있는지 테스트하고 싶지 않습니다. 이로 인해 명령이 복잡해지지만 0
모든 것이 계획대로 진행되면 명령이 반환될 수 있습니다. 이와 같이:
find . ! -path ./folder1 \
! -path './folder1/*' \
! -path ./file1 \
! -path ./folder2/subfolder/onefile \
\( ! -type d -o -empty \) \
-delete
find
지원할 수 있는 자금이 충분하며 -delete
아마도 -empty
그렇게 될 것입니다 -regex
. 내 Debian의 GNU는 find
다음을 수행할 수 있습니다:
find . ! -regex '\./folder1/*.*\|\./file1\|\./folder2/subfolder/onefile' -delete
노트:
onefile
find
이로 인해 삭제subfolder
또는 존재가 방지됩니다folder2
. 이러한 디렉터리의 존재 여부 에 관계없이 이러한 디렉터리를 보존하려면 더 많은 패턴(아래 참조)이나 더 복잡한 정규식이 필요합니다onefile
. 더 복잡한 정규식을 사용한 변형:find . ! -regex '\./folder1/*.*\|\./file1\|\./folder2\(/subfolder\(/onefile\)?\)?' -delete
보너스로, 이 개선 사항은 "0이 아닌 종료 상태" 문제를 해결합니다.
-path
glob과 같은 패턴 일치 표기법을 사용합니다(?
단일 문자와 일치하고*
0개 이상의 문자와 일치).-regex
정규식을 사용합니다(.
단일 문자와 일치하고.*
0개 이상의 문자와 일치).-path
-regex
파일의 전체 경로 와 일치합니다. 효과적인 패턴을 디자인하려면find
어떤 경로가 사용될지 알아야 합니다 . 힌트:find
시작점이 아닌 경로에는 후행 슬래시를 사용하지 않을 의무가 있습니다. 그래서 () 와 files-path
에 대해./folder1
별도의 모드를 사용합니다./folder1/*
.- 반면에 시작점은 규정된 대로 사용됩니다. 시작점이 이면 모든 경로는 자신에 대한 경로를 제외하고
.
시작됩니다 . 그러면 가 됩니다. 시작점이 이면 모든 경로가 시작됩니다../
.
.
./
./
내 테스트에서는
-delete
자동으로 처리.
하고 삭제하지 않으며 오류를 발생시키지 않으므로 제외할 필요가 없습니다.
. 반면에 오류가 발생합니다./
. 이 동작이 얼마나 신뢰할 수 있는지 잘 모르겠습니다. 의심스러운 경우에는 명시적으로 제외하십시오.
. 특히 의미 있는 종료 상태를 찾고 있는 경우에는 더욱 그렇습니다.정규식 유형이 거의 없습니다.. 예를 들어
-regextype posix-extended
before를 사용할 수 있습니다! -regex
.내가 생각 해낸 가장 간단한 명령(휴대용은 아니지만):find . -regextype posix-extended \ ! -regex './folder1(/.*)?|./file1|./folder2(/subfolder(/onefile)?)?' \ -delete
.
의도적으로 (리터럴 도트) 대신 (와일드카드)를\.
선두 지점으로 사용했습니다.
. 시작점이 이므로.
모든 경로는.
확실히 로 시작하므로 와일드카드는 를 제외한 어떤 것과도 일치하지 않습니다.
.\.
형식적인 정확성을 선호하는 경우 사용하세요.너무 많이 삭제하지 않으려면 명령을 "테스트 실행"할 수 있습니다.
-delete
로 변경-print
하면 삭제하려는 항목이 표시됩니다. 이것은 다음과 같이 수정된 첫 번째 명령입니다.find . ! -path ./folder1 ! -path './folder1/*' ! -path ./file1 ! -path ./folder2/subfolder/onefile -print
또는 이전 테스트를 모두 무효화전체적으로(이는 변경해야 할 사항이 무엇인지 알지 않는 한 개별적으로 부정하는 것과는 다릅니다. 비교하십시오.이것도착하다이것) 변경하여 무엇이 살아남는지 확인
-delete
합니다-print
.find . ! \( ! -path ./folder1 ! -path './folder1/*' ! -path ./file1 ! -path ./folder2/subfolder/onefile \) -print
따옴표를 사용하지 않으면
./folder1/*
오류가 발생합니다. 쉘은 확장을 시도합니다*
.
-path
예POSIX 요구 사항하지만 -delete
그리고 -regex
아니오 -empty
. 때로는 -exec rm {} +
대신 사용할 수도 있지만 필요한 디렉토리가 삭제되지는 않습니다 -delete
. 예, 디렉토리를 삭제할 수도 있지만 전체 요점 도 삭제되고 무효화됩니다.rm
rmdir
rm -r
rm -r ./folder2
./folder2/subfolder/onefile
-delete
우리의 기본 접근 방식은 다음 사항 없이도(몇 가지 개선 사항을 적용하여) 구현할 수 있습니다.
find . -depth \
! -path . \
! -path ./folder1 \
! -path './folder1/*' \
! -path ./file1 \
! -path ./folder2 \
! -path ./folder2/subfolder \
! -path ./folder2/subfolder/onefile \
\( \( ! -type d -exec rm {} + \) -o \( -type d -exec rmdir {} + \) \)
./folder2
을 명시적으로 제외함으로써 ./folder2/subfolder
명령이 의미 있는 종료 상태를 반환하도록 하고 이러한 디렉토리가 onefile
존재하지 않더라도 보존합니다.
onefile
존재하지 않는 디렉터리를 삭제하려면 추가 패턴을 사용하지 마세요. 연구 --ignore-fail-on-non-empty
옵션 rmdir
. POSIX에는 이 옵션이 필요하지 않습니다.
나는 마지막 명령이 빡빡하다고 말하지 않을 것입니다. 나는 그것이 -regex
더 좋다.
답변2
이러한 잠재적으로 파괴적인 작업의 경우 수동으로 신중하게 수행합니다. 전체 경로가 포함된 모든 파일 목록을 가져오고, 남아 있어야 하는 파일을 편집하거나( grep -v
또는 즐겨 사용하는 텍스트 편집기를 사용하여 누락된 파일이 있는지 확인합니다) ; 목록을 피드합니다( rm
목록이 큰 경우 사용해야 할 수도 있음). xargs(1)
공백이나 기타 특이한 문자가 포함된 파일 이름에 주의하세요!