Descompactando arquivos que estão voando através de um tubo

36

Posso fazer com que o descompactador ou qualquer outro programa semelhante funcione na saída padrão? A situação é que estou baixando um arquivo zip, que deve ser descompactado na hora.

Problema relacionado: Como Canalizar um arquivo baixado para a saída padrão no bash?

    
por Alex 16.06.2009 / 14:32

10 respostas

22

Enquanto um arquivo zip é, na verdade, um formato de contêiner, não há motivo para que ele não possa ser lido de um pipe (stdin) se o arquivo puder caber na memória com bastante facilidade. Aqui está um script Python que pega um arquivo zip como entrada padrão e extrai o conteúdo para o diretório atual ou para um diretório especificado, se especificado.

import zipfile
import sys
import StringIO
data = StringIO.StringIO(sys.stdin.read())
z = zipfile.ZipFile(data)
dest = sys.argv[1] if len(sys.argv) == 2 else '.'
z.extractall(dest)

Esse script pode ser reduzido a uma linha e criado como um alias.

alias unzip-stdin="python -c \"import zipfile,sys,StringIO;zipfile.ZipFile(StringIO.StringIO(sys.stdin.read())).extractall(sys.argv[1] if len(sys.argv) == 2 else '.')\""

Agora descompacte a saída do wget facilmente.

wget http://your.domain.com/your/file.zip -O - | unzip-stdin target_dir
    
por 15.06.2011 / 21:44
17

É improvável que isso funcione como você espera. O zip não é apenas um formato de compactação, mas também um formato de contêiner. Ele acumula os trabalhos de tar e gzip.bzip2 em um. Dito isto, se o seu zip tiver um único arquivo, você pode usar o unzip -p para extrair os arquivos para o stdout. Se você tiver mais de um arquivo, não há como dizer onde eles começam e param.

Quanto à leitura de stdin, a página man unzip tem esta frase:

Archives read from standard input are not yet supported, except with funzip (and then only the first member of the archive can be extracted).

Você pode ter alguma sorte com o funzip.

    
por 16.06.2009 / 14:45
7

O que você quer fazer é fazer com que unzip pegue um arquivo ZIP em sua entrada padrão e não como um argumento. Isso geralmente é facilmente suportado pelo tipo de ferramentas gzip e tar com um argumento - . Mas o padrão unzip não faz isso (embora suporte a extração para um pipe). No entanto, nem tudo está perdido ...

Veja a página de manual do funzip .

funzip without a file argument acts as a filter; that is, it assumes that a ZIP archive (or a gzip'd file) is being piped into standard input, and it extracts the first member from the archive to stdout. When stdin comes from a tty device, funzip assumes that this cannot be a stream of (binary) compressed data and shows a short help text, instead. If there is a file argument, then input is read from the specified file instead of from stdin.

Given the limitation on single-member extraction, funzip is most useful in conjunction with a secondary archiver program such as tar(1). The following section includes an example illustrating this usage in the case of disk backups to tape.

Isto vai bem com a ideia de que a maioria dos arquivos Linux são normalmente TAR'ed e então ZIP de alguma forma (gzip, bzip, et al). Isso funcionará para você se você tiver um tar.ZIP .

Vale a pena notar que funzip foi escrito pelo autor original da Info-ZIP, Mark Adler. Ele escreve na página do homem do funzip,

this functionality should be incorporated into unzip itself (future release).

no entanto, essa atualização não é vista por aí. Eu suspeito que Mark achou desnecessário, já que outros métodos de arquivamento funcionavam facilmente com o TAR.

    
por 16.06.2009 / 14:46
6

Eu gosto de usar o curl porque ele é instalado por padrão (o -L é necessário para redirecionamentos que ocorrem com frequência):

curl -L http://example.com/file.zip | bsdtar -xvf - -C /path/to/directory/

No entanto, bsdtar não está instalado por padrão e não consegui fazer com que funzip funcione.

    
por 05.03.2016 / 16:47
4

Não é possível com o Info-Zip, que é a implementação mais comum de OSS. Mais importante ainda, não é recomendado devido às construções de arquivos ZIP.

Se uma mudança de formato for viável, considere o uso de tar (1). É muito feliz com a entrada / saída transmitida e, de fato, espera por padrão.

Além disso, você geralmente pode informar se os aplicativos esperam entrada / saída em fluxo especificando "-" para um nome de arquivo. O Info-Zip, como você pode imaginar, não trata isso como um argumento válido.

    
por 16.06.2009 / 14:53
4

No zsh, você pode fazer o seguinte:

unzip =( curl http://example.com/someZipFile.zip )
    
por 14.11.2013 / 23:09
4

Este é um repost do meu responda a uma pergunta semelhante:

O formato de arquivo ZIP inclui um diretório (índice) no final do arquivo. Este diretório diz onde, dentro do arquivo, cada arquivo está localizado e, assim, permite acesso rápido e aleatório, sem ler o arquivo inteiro.

Isto parece representar um problema ao tentar ler um arquivo ZIP através de um pipe, em que o índice não é acessado até o final e assim membros individuais não podem ser corretamente extraídos até depois que o arquivo tenha sido lido inteiramente e seja não está mais disponível. Como tal, não parece surpreendente que a maioria dos descompactadores ZIP simplesmente falhe quando o arquivo é fornecido através de um pipe.

O diretório no final do arquivo não é o único local onde as informações meta do arquivo são armazenadas no arquivo. Além disso, entradas individuais também incluem essas informações em um cabeçalho de arquivo local, para fins de redundância.

Embora nem todo descompactador ZIP use cabeçalhos de arquivos locais quando o índice está indisponível, o front end tar e cpio para libarchive (também conhecido como bsdtar e bsdcpio) pode e vai fazê-lo ao ler um pipe , o que significa que o seguinte é possível:

wget -qO- http://example.org/file.zip | bsdtar -xvf-
    
por 16.04.2014 / 19:54
1

Na verdade, precisei de algo um pouco mais complexo - extraia um arquivo específico, se existir. A dificuldade é que o fluxo de arquivos de entrada pode não ser um arquivo zip e, nesse caso, eu precisava continuar com o pipe. Aqui está a minha solução (graças principalmente à solução de Jason R. Coombs)

python -c "import zipfile,sys,StringIO
data=sys.stdin.read()
try:
    z=zipfile.ZipFile(StringIO.StringIO(data))
    z.open(\"$1\")
    sys.stdout.write(z.read(\"$1\"))
except (RuntimeError, zipfile.BadZipfile):
    sys.stdout.write(data)"

Guardei isto como um ficheiro com o nome "effpoptp" (não é um nome simples) na pasta "/ bin" da minha máquina, pelo que o teste é assim:

cat defaultModel.mwb|effpoptp "document.mwb.xml"

O objetivo é controlar os arquivos do MySQL Workbench de versão, onde o arquivo pode ser o arquivo xml nomeado como o arquivo do ambiente de trabalho ou o arquivo completo do ambiente de trabalho.

    
por 13.11.2013 / 19:01
1

O mais simples utilitário comum disponível que fará isso é jar , que presumirá que STDIN está sendo usado se você não passar nenhum arquivo args. Ele também aceita argumentos semelhantes ao programa tar para operações.

por exemplo. listar o conteúdo de um arquivo

curl https://my.example.com/file.zip | jar t

Embora o Java nem sempre esteja instalado, nessas máquinas, jar é definitivamente o método mais conveniente para fazer isso.

    
por 04.06.2017 / 14:15
1

Repost de minha resposta :

O unzip do BusyBox pode pegar stdin e extrair todos os arquivos.

wget -qO- http://downloads.wordpress.org/plugin/akismet.2.5.3.zip | busybox unzip -

O traço após unzip é usar stdin como entrada.

Você pode até mesmo,

cat file.zip | busybox unzip -

Mas isso é apenas redundante de unzip file.zip .

Se a sua distro usar o BusyBox por padrão (por exemplo, Alpine), basta executar unzip - .

    
por 11.10.2018 / 14:13