Windows에서 생성된 ZIP을 Linux로 변환(내부 경로 문제)

Windows에서 생성된 ZIP을 Linux로 변환(내부 경로 문제)

내 Windows 컴퓨터에서 (내 통제가 불가능함) .zip을 만들었습니다. zip 파일에는 압축을 풀 때 보존해야 하는 경로가 포함되어 있습니다.

그러나 압축을 풀면 모든 파일이 다음과 같이 끝납니다.
unzip_dir/\window\path\separator\myfile.ext

옵션이 있는 것과 없는 것 모두 시도해 보았습니다 -j. 내 문제는 나야필요아래의 경로 정보입니다 \window\path\separator\. 압축을 풀 때 이 파일 구조를 만들어야 합니다.

스크립트에서 파일을 쉽게 생성 mv하고 뒤집을 수 \있지만 /대상 경로 디렉토리가 존재하지 않는다는 오류가 발생합니다. 현재 해결 방법은 mkdir -p경로( 변환 \/)를 선택한 다음 cp파일을 해당 경로로 전송하는 것입니다.

하지만 파일이 너무 많아서 mkdir -p각 파일에 대한 이러한 중복된 명령문으로 인해 작업 속도가 정말 느려질 수 있습니다.

Windows 경로가 포함된 zip 파일을 Linux 경로로 변환하는 더 우아한 방법이 있습니까?

답변1

7z rn슬래시가 포함되도록 아카이브의 파일 이름을 바꾸는 데 사용됩니다 . 그런 다음 아카이브를 추출하면 디렉터리가 생성됩니다.

파일 이름을 바꾸려면 슬래시가 포함된 아카이브의 파일 경로를 나열하고 awk백슬래시를 슬래시로 변경하는 등의 대체 문자열 목록을 생성합니다.

7z rn windows.zip $(7z l windows.zip | grep '\\' | awk '{ print $6, gensub(/\\/, "/", "g", $6); }' | paste -s)

답변2

Windows에서 zip 파일을 만들 때 (이식 가능한) 슬래시가 있기 때문에 zip 파일을 만들 때 문제가 발생한 것 같습니다.

zip.exe -r pip pip
updating: pip/ (244 bytes security) (stored 0%)
  adding: pip/pip.log (164 bytes security) (deflated 66%)

그러나 이제 파일 이름에 백슬래시가 있는 "path"가 포함된 파일이 있으므로 다음 프로그램을 실행할 수 있습니다 unzip_dir.

#! /usr/bin/env python

# already created directories, walk works topdown, so a child dir
# never creates a directory if there is a parent dir with a file.
made_dirs = set()

for root, dir_names, file_names in os.walk('.'):
    for file_name in file_names:
        if '\\' not in file_name:
            continue
        alt_file_name = file_name.replace('\\', '/')
        if alt_file_name.startswith('/'):
            alt_file_name = alt_file_name[1:]  # cut of starting dir separator
        alt_dir_name, alt_base_name = alt_file_name.rsplit('/', 1)
        print 'alt_dir', alt_dir_name
        full_dir_name = os.path.join(root, alt_dir_name)
        if full_dir_name not in made_dirs:
            os.makedirs(full_dir_name)  # only create if not done yet
            made_dirs.add(full_dir_name)
        os.rename(os.path.join(root, file_name),
                  os.path.join(root, alt_file_name))

이는 프로그램 시작 디렉터리 아래의 모든 디렉터리에 있는 파일을 처리합니다. 설명하는 문제를 고려할 때 unzip_dir시작할 하위 디렉터리가 없고 프로그램은 현재 디렉터리의 파일에 대해서만 반복할 수 있습니다.

답변3

이것은 @madmuffin의 수정 사항( FileExistsError: [Errno 17] File exists및 누락된 os모듈 가져오기), Python 3 수정 사항( SyntaxError: Missing parentheses in call to 'print') 및 누락된 모듈 가져오기에 대한 수정 사항 errno( NameError: name 'errno' is not defined)을 포함하는 @anton의 답변에 대한 업데이트일 뿐입니다.

#! /usr/bin/env python

import os
import errno

# already created directories, walk works topdown, so a child dir
# never creates a directory if there is a parent dir with a file.
made_dirs = set()

for root, dir_names, file_names in os.walk('.'):
    for file_name in file_names:
        if '\\' not in file_name:
            continue
        alt_file_name = file_name.replace('\\', '/')
        if alt_file_name.startswith('/'):
            alt_file_name = alt_file_name[1:]  # cut of starting dir separator
        alt_dir_name, alt_base_name = alt_file_name.rsplit('/', 1)
        print('alt_dir', alt_dir_name)
        full_dir_name = os.path.join(root, alt_dir_name)
        if full_dir_name not in made_dirs:
            try:
                os.makedirs(full_dir_name)
            except OSError as exc:
                if exc.errno == errno.EEXIST and os.path.isdir(full_dir_name):
                    # the pass already exists and is a folder, let's just ignore it
                    pass
                else:
                    raise 
            made_dirs.add(full_dir_name)
        os.rename(os.path.join(root, file_name),
                  os.path.join(root, alt_file_name))

답변4

표준에는 모든 슬래시가 슬래시여야 함을 명시하고 있습니다.

https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT

4.4.17.1 The name of the file, with optional relative path.
   The path stored MUST NOT contain a drive or
   device letter, or a leading slash.  All slashes
   MUST be forward slashes '/' as opposed to
   backwards slashes '\' for compatibility with Amiga
   and UNIX file systems etc.  If input came from standard
   input, there is no file name field.
   

다음은 문제가 없는 zip 파일을 수정하고 이전 답변에서 누락된 공백도 처리하는 스크립트입니다.

#!/bin/sh
CMD_INSTRUCTIONS=$(7z l -ba -slt "$1" | grep '\\' | sed 's/^Path = //g' | sed 's/.*/"&"/' | gawk '{ print $0, gensub(/\\/, "/", "g", $0); }' | sed 's|\\|\\\\|g' | paste -s -)
CMD_7Z="7z rn \"$1\" $CMD_INSTRUCTIONS"
eval "$CMD_7Z"

원천:

관련 정보