Converta um ZIP criado pelo Windows em Linux (problema de caminhos internos)

4

Eu tenho um .zip criado em uma máquina Windows (fora do meu controle). O arquivo zip contém os caminhos que preciso preservar quando descompactar.

No entanto, quando eu descompactar, todos os arquivos acabam como:% unzip_dir/\window\path\separator\myfile.ext

Eu tentei os dois, com e sem a opção -j . Meu problema é que preciso dessas informações do caminho em \window\path\separator\ . Eu preciso que essa estrutura de arquivos seja criada quando eu descompactar.

Eu posso mv do arquivo e virar o \ para / facilmente em um script, mas há erros que os diretórios de caminho de destino não existem. Minha solução alternativa por enquanto é mkdir -p dos caminhos (após a conversão de \ para / ) e, em seguida, cp dos arquivos para esses caminhos.

Mas há muitos arquivos, e essas declarações mkdir -p redundantes para cada arquivo realmente atrapalham as coisas.

Existe alguma maneira mais elegante de converter um arquivo zip com caminhos do Windows em caminhos do Linux?

    
por Slav 05.11.2014 / 17:35

3 respostas

2

Acho que algo deu errado com a criação do arquivo zip, porque quando eu crio um arquivo zip no Windows tem barras (portáteis):

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

Mas agora que você tem os arquivos com nomes de arquivos que contêm "caminhos" com barras invertidas, você pode executar o seguinte programa em 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))

Isso lida com arquivos em qualquer diretório sob o diretório de onde o programa é iniciado. Dado o problema que você descreve, o unzip_dir provavelmente não tem nenhum subdiretório para começar, e o programa poderia apenas passar por cima dos arquivos apenas no diretório atual.

    
por 05.11.2014 / 18:09
2

Esta é apenas uma atualização da resposta de @ anton, que inclui correções de @madmuffin ( FileExistsError: [Errno 17] File exists e falta de os module import), uma correção para python 3 ( SyntaxError: Missing parentheses in call to 'print' ) e uma correção para a falta de errno importação de módulo ( NameError: name 'errno' is not defined ).

#! /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))
    
por 18.05.2017 / 02:30
2

Use 7z rn para renomear os arquivos dentro do archive para que eles tenham uma barra. Então, quando você extrair o arquivo, os diretórios serão criados.

Para renomear os arquivos, liste os caminhos dos arquivos contidos no arquivo contendo barras e gere uma lista de sequências de substituição que alteram a barra invertida para uma barra usando awk , por exemplo.

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

Tags