Decomprimere i file che volano attraverso una pipe


40

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?


Sembra che dovrebbe essere fattibile, ma sembra che sia possibile estrarre una zip e reindirizzare il file a un altro comando se la zip contiene solo un singolo file. Volevo estrarre un file specifico da uno zip multi-file. Invece di eseguire il piping, sono passato al concatenamento di più comandi 'decomprimere file.zip / percorso / file && dostuff / percorso / file && rm -rf / percorso' Pur non rispondendo alla domanda originale e risultando nella creazione di file temporanei, ha soddisfatto il mio bisogno.
Stan Kurdziel,

Dai un'occhiata a Pigz. Lo usiamo in una pipa. andrew.tumblr.com/post/2316602611
dmourati,

Risposte:


22

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 script 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

1
Tu e Python Rock !!!
Farid Nouri Neshat,

4
Nice one-liner, e +1 per menzionare che il file deve adattarsi alla memoria. (Sfortunatamente non c'è modo di decomprimere un file pkzip a causa della struttura del formato del file).
lxgr

2
tieni presente che questo buffer tutto ciò che è in memoria prima di estrarlo
William Casarin,

1
non vi è alcun motivo per cui non possa essere letto come flusso se il file può rientrare nella memoria abbastanza facilmente non è molto preciso. Il motivo per cui sei costretto a bufferizzare l'intero archivio zip in memoria prima di estrarre il contenuto è specificamente perché non può essere letto come flusso. Naturalmente, può essere comunque utile evitare di scrivere l'archivio zip in un file.
Håkan Lindqvist,

Questo non è un flusso, stai leggendo l'intero file in memoria usando il .read()metodo
Romuald Brunet

18

È 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 la tua 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.


Se zip contiene più file all'interno, allora -p può stampare un singolo file usando il nome del file come parametro: decomprimere -p temp.zip file-inside-zip
Taavi Ilves il

7

Quello che vuoi fare è unzipprendere un file ZIPped sul suo input standard piuttosto che come argomento. Questo di solito è facilmente supportato da gzipe tartipo di strumenti con un -argomento. Ma lo standard unzipnon lo fa (tuttavia, supporta l'estrazione in una pipe). Tuttavia, non tutto è perduto ...

Guarda la pagina di manuale di funzip .

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 a 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 solitamente 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è stato 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.


Solo un commento; alcune persone vorrebbero Python o qualsiasi lingua come opzione per decomprimere. Un primo esempio è Heroku che non include tar o decomprime sul suo sistema. Una soluzione consiste nell'utilizzare jar installando Java che è consentito.
Nick,

C'è di più su come gestire le limitazioni di funzip e strumenti simili (in particolare la capacità di mostrare solo il primo membro di un archivio) in questa risposta: unix.stackexchange.com/a/211286/77539
Joshua Goldberg

6

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

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

Tuttavia, bsdtarnon è installato per impostazione predefinita e non sono riuscito funzipa lavorare.


Funziona bene anche con più file
jonnor

5

Questo è un ripubblicare della 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 rappresentare 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 è l' unica posizione in cui sono archiviate le meta informazioni sul file. 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 in libarchive (aka bsdtar e bsdcpio) possono e lo faranno durante la lettura attraverso una pipe, il che significa che è possibile quanto segue:

wget -qO- http://example.org/file.zip | bsdtar -xvf-

4

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, di fatto, lo prevede per impostazione predefinita.

Inoltre, spesso è possibile stabilire 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

In zsh, puoi fare quanto segue:

unzip =( curl http://example.com/someZipFile.zip )

3

L'utilità comune più semplice disponibile che lo farà è jar, che presumerà che STDIN sia usato se lo passi senza file args. Prende anche argomenti simili al tarprogramma per le operazioni.

ad es. elencare il contenuto di un archivio

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

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


3

Repost della mia risposta :

BusyBox unzippuò 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 unzip file.zip.

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


1

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" sul mio computer, 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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.