sviluppo-web-qa.it

Decomprimere i file che volano attraverso una pipe

Posso fare in modo che decomprimi o programmi simili funzionino sull'output standard? La situazione è che sto scaricando un file Zip, che dovrebbe essere decompresso al volo.

Problema correlato: Come installo un file scaricato all'output standard in bash?

43
Alex

Mentre un file Zip è in realtà un formato contenitore, non c'è motivo per cui non possa essere letto da una pipe (stdin) se il file può adattarsi alla memoria abbastanza facilmente. Ecco uno Python che accetta un file Zip come input standard ed estrae il contenuto nella directory corrente o in una directory specificata se specificato.

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)

Questo script può essere minimizzato su una riga e creato come 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 '.')\""

Ora decomprimi facilmente l'output di wget.

wget http://your.domain.com/your/file.Zip -O - | unzip-stdin target_dir
22
Jason R. Coombs

È improbabile che ciò funzioni come previsto. Zip non è solo un formato di compressione, ma anche un formato contenitore. Raggruppa i lavori di tar e gzip.bzip2 in uno. Detto questo, se Zip ha un singolo file, puoi usare unzip -p per estrarre i file su stdout. Se hai più di un file, non c'è modo per te di dire dove iniziano e si fermano.

Per quanto riguarda la lettura da stdin, la pagina man di decompressione ha questa frase:

Gli archivi letti dallo standard input non sono ancora supportati, tranne con funzip (e quindi solo il primo membro dell'archivio può essere estratto).

Potresti avere un po 'di fortuna con Funzip.

18
David Pashley

Quello che vuoi fare è, fare in modo che unzip prenda un file ZIPped sul suo input standard piuttosto che come argomento. Questo di solito è facilmente supportato da gzip e tar tipo di strumenti con un - discussione. Ma lo standard unzip non lo fa (tuttavia, supporta l'estrazione in una pipe). Tuttavia, non tutto è perduto ...

Guarda funzip pagina di manuale.

funzip senza argomento file funge da filtro; ovvero, presuppone che un archivio Zip (o un file gzip'd) venga reindirizzato all'input standard ed estrae il primo membro dall'archivio su stdout. Quando stdin proviene da un dispositivo tty, funzip presume che questo non possa essere un flusso di dati compressi (binari) e mostra invece un breve testo di aiuto. Se esiste un argomento file, l'input viene letto dal file specificato anziché da stdin.

Data la limitazione sull'estrazione di un singolo membro, funzip è molto utile in combinazione con un programma di archiviazione secondario come tar (1). La sezione seguente include un esempio che illustra questo utilizzo nel caso di backup su disco su nastro.

Questo va bene con l'idea che la maggior parte degli archivi di Linux sono di solito TAR e quindi ZIPped in qualche modo (gzip, bzip, et al). Questo funzionerà per te se hai un tar.Zip.


Vale la pena notare che funzip è scritto dall'autore originale di Info-Zip Mark Adler. Scrive nella pagina man di funzip,

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

tuttavia, nessun aggiornamento di questo tipo è visibile in giro. Sospetto che Mark lo abbia ritenuto superfluo poiché altri metodi di archiviazione hanno funzionato facilmente con TAR.

7
nik

Mi piace usare il ricciolo perché è installato di default (il -L è necessario per i reindirizzamenti che si verificano spesso):

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

Tuttavia, bsdtar non è installato per impostazione predefinita e non sono riuscito a far funzionare funzip.

7
Todd Partridge

Questo è un repost di la mia risposta a una domanda simile:

Il formato del file Zip include una directory (indice) alla fine dell'archivio. Questa directory indica dove si trova ogni file all'interno dell'archivio e consente quindi un accesso rapido e casuale, senza leggere l'intero archivio.

Ciò sembra costituire un problema quando si tenta di leggere un archivio Zip attraverso una pipe, in quanto l'indice non è accessibile fino alla fine e quindi i singoli membri non possono essere estratti correttamente fino a quando il file non è stato letto interamente e non è più disponibile . Pertanto, non sorprende che la maggior parte dei decompressori Zip non riesca semplicemente quando l'archivio viene fornito attraverso una pipe.

La directory alla fine dell'archivio non è la posizione solo in cui sono archiviate le meta informazioni del file nell'archivio. Inoltre, le singole voci includono anche queste informazioni in un'intestazione di file locale, a fini di ridondanza.

Sebbene non tutti i decompressori Zip utilizzeranno le intestazioni di file locali quando l'indice non è disponibile, i front-end tar e cpio terminano con libarchive (aka bsdtar e bsdcpio) possono e saranno durante la lettura di una pipe, ciò significa che è possibile:

wget -qO- http://example.org/file.Zip | bsdtar -xvf-
5
ruario

In zsh, puoi fare quanto segue:

unzip =( curl http://example.com/someZipFile.Zip )
4
Ian Robertson

L'utilità comune più semplice disponibile che farà questo è jar, che presumerà che STDIN sia usato se non lo passi nessun file args. Accetta anche argomenti simili al programma tar per le operazioni.

per esempio. elenca il contenuto di un archivio

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

Mentre Java non è sempre installato, su quelle macchine in cui si trova, jar è sicuramente il metodo più conveniente per farlo.

4
Adrian

Non è possibile con Info-Zip che è l'implementazione OSS più comune. Ancora più importante, tuttavia, non è raccomandato a causa dei costrutti di archivi Zip.

Se un cambio di formato è praticabile per te, considera invece l'uso di tar (1). È abbastanza soddisfatto dell'input/output in streaming e, in effetti, lo prevede per impostazione predefinita.

Inoltre, puoi spesso sapere se le applicazioni prevedono input/output in streaming specificando "-" per un nome file. Info-Zip, come puoi immaginare, non lo considera un argomento valido.

4
Dan Carley

Repost of la mia risposta :

unzip di BusyBox può prendere stdin ed estrarre tutti i file.

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

Il trattino dopo unzip è usare stdin come input.

Puoi persino

cat file.Zip | busybox unzip -

Ma questo è solo ridondante di unzip file.Zip.

Se la tua distribuzione utilizza BusyBox per impostazione predefinita (ad es. Alpine), esegui semplicemente unzip -.

3
Saftever

In realtà avevo bisogno di qualcosa di un po 'più complesso: estrarre un file specifico se esiste. La difficoltà sta nel fatto che il flusso del file di input potrebbe non essere un file Zip e, in tal caso, avevo bisogno che continuasse attraverso la pipe. Ecco la mia soluzione (grazie soprattutto alla soluzione 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)"

L'ho salvato come file chiamato "effpoptp" (non un nome semplice) nella cartella "/ bin" sulla mia macchina, quindi testarlo è così:

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

Lo scopo è controllare la versione dei file di MySQL Workbench, in cui il file potrebbe essere il file xml denominato file di workbench o il file di workbench completo.

1
SEoF