zip 파일을“확실 해제”하는 방법은 무엇입니까?


52

비어 있지 않은 폴더에 zip 파일을 추출했습니다. zip 파일에는 대상 디렉토리의 기존 트리와 병합 된 많은 파일과 깊은 계층 구조가 있습니다. 이미 존재하는 파일과 디렉토리를 손상시키지 않고 압축을 풀어 생성 한 파일과 디렉토리를 어떻게 제거 할 수 있습니까? 물론, 여전히 병합 한 zip 파일이 있으므로 정보가 있습니다.


받아 주셔서 감사합니다.하지만 @jjin의 아이디어였습니다. 에 대한 lq옵션을 알지 못했지만 unzizp그의 주요 답변 주위에 고전적인 * nix 트릭을 추가했습니다.
terdon

괜찮아, 난 그다지 신경 쓰지 않아 어쨌든 다른 버전의 공백 처리를 추가했습니다.
jjlin

@terdon 그래 ... 나도 jjlin의 대답을 찬성했지만 하나의 답만 받아 들일 수있다.
mafp

나중에 참조 할 수 있도록 항상 익숙하지 않은 형식의 아카이브를 사용하여 다음 중 하나를 수행하십시오. 모든 것을 가진 최상위 디렉토리없이 만들어진 아카이브는 잘못된 형식입니다. 타르로 끝났을 때, 그들은 실제로 타르 폭탄이라고 불립니다.
Joe

@Joe 용도가 있습니다. 예를 들어 LaTeX 패키지는 foo.tds.zip형태로 제공 될 수 있습니다 . 이 zip은 TEXMF 트리에 병합되어 매우 편리합니다. 그러나 그러한 패키지를 제거하려면 내가 설명한 문제가 발생합니다.
mafp

답변:


28

jjlin 의 답변은 갈 길입니다. 디렉토리에 대한 몇 가지 선택 사항을 추가하고 싶습니다.

  • 디렉토리가없는 추출 된 파일을 모두 삭제하십시오 .

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done
  • 추출 된 파일 및 디렉토리 만 삭제

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done; rmdir *

    옵션이 없으면 rmdir빈 디렉토리 만 삭제하고 파일과 비어 있지 않은 폴더 만 남겨두고 안전하게 실행할 수 있습니다 *.

  • 추출 된 모든 항목을 삭제 하지만 각 삭제 전에 확인 메시지를 표시하십시오.

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm -ri "$n"; done; rmdir *

    -i플래그가 발생할 rm때마다 제거하기 전에 확인하도록, 당신은 예 또는 아니오를 선택할 수 있습니다

  • 추출 된 모든 디렉토리를 삭제하십시오 .

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm -rf "$n"; done

빈 디렉토리 삭제는 find: 로 쉽게 수행 할 수 있으며 find * -depth -type d -exec rmdir {} +모든 Directory not empty메시지를 무시 합니다. 이를 단축 법적 될 수 find * -type d -delete는 AS -delete옵션이 전환 -depth하지만 난 그 확인하지 않은 -delete비어 있지 않은 디렉토리를 삭제되지 않습니다.
Adrian Pronk 2013

@AdrianPronk 그것은하지 않습니다 :find: cannot delete './foo': Directory not empty
terdon

28

unzip -lqq <filename.zip>zip 파일의 내용을 나열하는 데 사용할 수 있습니다 . 여기에는 필터링해야 할 외부 정보가 포함됩니다. 나를 위해 작동하는 명령은 다음과 같습니다.

unzip -lqq file.zip | awk '{print $4;}' | xargs rm -rf

awk명령은 파일과 디렉토리의 이름 만 추출합니다. 그런 다음 결과가 xargs모든 항목을 삭제하도록 전달됩니다 . xargs rm -rf결과가 올바른지 확인하기 위해 명령을 드라 이런 (즉, 부품 생략)하는 것이 좋습니다 .

위 명령에는 공백이있는 경로를 처리하는 데 문제가 있습니다. 이 (더 복잡한) 버전은 다음을 수정해야합니다.

unzip -lqq file.zip | awk '{$1=$2=$3=""; sub(/ */, "", $0); printf "%s%s", $0, "\0"}' | xargs -0 rm -rf

이것은 이미 내가 생각한 것에 가깝지만 unzip -lqqzip에 포함 된 디렉토리도 나열합니다. 지금은 모든 디렉토리를 그대로 두겠습니다. 트리에서 빈 디렉토리를 모두 삭제하는 방법은 후속 질문 일 수 있습니다.
mafp

@mafp 디렉토리에 대한 좋은 지적입니다. grep -v '/$'파이프 라인에 추가 하여 디렉토리 삭제를 건너 뛸 수 있습니다 (모두 후행 슬래시가있는 AFAICT).
jjlin

@terdon 실제로 awk4 달러를 인쇄하면 전체 경로가 인쇄되지 않으므로 문제는에서 시작된다고 생각합니다 .
jjlin

나는 당신이 -rrm 옵션 을 사용해야한다고 생각하지 않습니다 . 특히 -f옵션 과 결합 될 때 문제를 묻는 것 같습니다 . -f이 시나리오 에서는 옵션을 전혀 사용하지 않습니다 .
애드리안 프 롱크

1
@jjlin : grep -v '/$'ZIP 파일에서 디렉토리 항목 만 생략합니다. ZIP 파일에는 일반 파일이지만 대상 폴더에는 기존 디렉토리 인 항목이 계속 포함됩니다. 이러한 이유로 생략하는 것이 현명 할 것입니다-r
애드리안 Pronk

11

switch를 사용하면 -Z1unzip은 한 줄에 정확히 하나의 파일을 나열합니다 (다른 것은 없습니다).

이런 식으로, 당신은 사용할 수 있습니다

unzip -Z1 | xargs -I {} rm '{}'

zip 파일에서 추출 된 모든 파일을 삭제합니다.

명령

unzip -Z1 | xargs -I {} rm -rf '{}'

디렉토리도 삭제되지만주의해야합니다. zip 파일을 추출하기 전에 디렉토리가 이미 존재하면 해당 디렉토리에있는 모든 기존 파일도 삭제됩니다.


어쨌든 zip 파일을 다시 추출하려면 이상한 파일 이름을 처리하는 다른 방법이 있습니다.

먼저 원래 압축을 푼 zip 파일을 추출하십시오.

unzip file.zip -d elsewhere

이제 실수로 파일을 추출한 디렉토리로 변경하고 다음 명령을 실행하십시오.

find elsewhere -type f -printf "%P\0" | xargs -0 -I {} rm '{}'
  • -type f 파일 만 찾습니다 (디렉토리 없음).

  • %P\0상대 경로 (제외 elsewhere/)와 그 뒤에 null 문자

  • -0xargs를 널 문자로 구분하여 행을 만듭니다. 이론적으로 파일 이름에는 개행 문자가 포함될 수 있으므로이 방법이 더 안정적입니다.


남은 디렉토리를 처리하기 위해 다음 명령을 실행할 수 있습니다.

find -type d -exec rmdir -p {} \; 2> /dev/null
  • -type d 디렉토리 만 찾습니다.

  • -exec rmdir -p {} \;rmdir -p {}발견 된 모든 디렉토리에 대해 실행 됩니다.

    {}발견 된 디렉토리이며, -p스위치는 rmdir이 빈 상위 디렉토리도 제거하도록합니다.

  • 2> /dev/null 비어 있지 않거나 이전에 삭제 된 디렉토리를 삭제하려고 할 때 발생하는 오류 메시지를 표시하지 않습니다.


관련 매뉴얼 페이지 :


zipinfo의 맨 페이지를 읽게 해 +1했습니다 .
terdon 2019

글쎄, 그게 좀 쉬워 졌어. :)
jjlin 2012

2

더 쉽고 안전한 솔루션이라고 생각합니다.

zip -m getmeoutofhere.zip `unzip -lqq myoriginalzipfile.zip`
rm getmeoutofhere.zip

수행중인 작업 : 역 따옴표로 묶인 unzip 명령은 원본 파일의 내용 목록을 생성합니다.

그런 다음 zip -m은 해당 목록을 사용하여 각 항목을 getmeoutofhere.zip에 추가 하고 원래 디렉토리에서 제거합니다. 이론적으로 myoriginalfile.zip에 필수적입니다.

단점은 unzip -lqq 가 추가 텍스트, 날짜, 시간, 파일 크기 등을 생성한다는 것입니다. 이러한 경우 zip -m은 오류 메시지를 생성하지만 아무런 영향을 미치지 않습니다 (같은 파일을 가진 경우가 아니라면) 이름).

이렇게하면 원래 압축 해제 중에 작성된 디렉토리는 제거되지 않습니다.


흥미로운 접근법은 더 탐구 할 것입니다.
mafp

1

아카이브의 수정 타임 스탬프가 추출 된 사본에 보존되지 않도록 파일을 추출한 경우 (추출 된 파일의 일반적인 수정 시간이 있음)이를 공격하는 올바른 방법은 수정 시간을 통하는 것입니다. 추출 된 모든 파일에는 해당 디렉토리에서 가장 최근에 수정 된 기존 파일보다 새로운 수정 시간 소인이 있습니다.

간단한 상황이 있습니다.

현재 디렉토리의 기존 파일 중 적어도 24 시간 동안 아무것도 터치하지 않았다고 가정하십시오. 지난 24 시간 동안 수정 된 것은 zip 파일에서 정크입니다.

$ find . -mtime -1 -print0 | xargs -0 rm

이것도 일부 디렉토리를 찾을 수 있지만, rm그대로 두게됩니다. 그들은 두 번째 패스에서 처리 할 수 ​​있습니다.

$ find . -mtime 1 -type d -print 0 | xargs -0 rmdir

최근에 수정 된 디렉토리는 zip으로 수정되었습니다. rmdir성공적으로 제거 되면 비어있는 것입니다. zip에 의해 터치 된 빈 디렉토리는 아마도 그 디렉토리에 의해 생성되었을 것입니다. 100 % 확신 할 수는 없습니다. 압축 해제 작업이 일부 파일을 비어있는 기존 디렉토리에 넣을 수 있습니다.

경우 find트리에서 파일이 너무 최근에 수정 되었기 때문에 '의 24 시간 단위는 일을 위해 충분하지 않습니다, 나는 다음 간단한 무언가를 생각 하는데요 : 압축 해제 작업이 기존의 하위 디렉토리에 아무것도 넣지 않았다고 가정합니다. 즉, 압축이 풀린 모든 파일은 최상위 레벨의 파일이거나 이전에 없었던 새로운 하위 디렉토리이므로 Zip의 자료 만 포함합니다. 그때:

# list directory in descending order of modification time
$ ls -1t > filelist  # descending order of modification time

이제 filelist텍스트 편집기에서 열고 zip에서 나오지 않은 목록의 첫 번째 항목을 결정합니다. 해당 항목과 그 이후의 모든 항목을 삭제합니다. 남아있는 것은 우편 번호에서 온 파일과 디렉토리입니다. 먼저 이름의 공백과 이스케이프해야 할 따옴표 발생과 같은 문제를 육안으로 검사합니다. 그런 다음 필요한 경우 모든 것을 따옴표로 묶을 수 있습니다. 다음은 Vim을 사용한다고 가정합니다.

:%s/.*/"&"/

그런 다음 큰 줄로 묶으십시오.

:%j

이제 그 rm -rf앞에 삽입 하십시오 :

Irm - rf<ESC>

커서 아래에서 행을 쉘 명령으로 실행하십시오.

!!sh<Enter>

확실히, 나는 이미 존재하는 파일을 지우거나 파일 이름 문제로 인해 망할 위험으로 인해이 작업 단계를 자동화하지 않습니다.

zip의 경로 목록을 얻는 명확한 경로를 찾으려면 파일로 캡처하고 매우 신중하게 살펴보고 필요한 편집을 수행 한 후 제거로 변환하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.