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%)

ただし、ファイル名にバックスラッシュがある「パス」を含むファイルがあるので、次のプログラムを実行できます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')、および不足しているモジュールのインポートに対する修正errnoNameError: 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"

源泉:

関連情報