Entpacken von Dateien, die durch eine Pipe eingedrungen sind

39

Kann ich mit der Standardausgabe Entpacken oder ähnliche Programme ausführen? Die Situation ist, dass ich eine Zip-Datei herunterlade, die im laufenden Betrieb entpackt werden soll.

Zugehöriges Problem: Wie leite ich eine heruntergeladene Datei in bash an die Standardausgabe weiter?

Alex
quelle
Dies schien machbar zu sein, aber es scheint nur möglich zu sein, eine Zip zu extrahieren und die Datei an einen anderen Befehl weiterzuleiten, wenn die Zip nur eine einzige Datei enthält. Ich wollte eine bestimmte Datei aus einer ZIP-Datei mit mehreren Dateien extrahieren. Anstelle von Piping habe ich mehrere Befehle verkettet: "unzip file.zip / pfad / datei && dostuff / pfad / datei && rm -rf / pfad". Die ursprüngliche Frage wurde nicht beantwortet und es wurden temporäre Dateien erstellt brauchen.
Stan Kurdziel
Schau dir Pigz an. Wir benutzen es in einer Pfeife. andrew.tumblr.com/post/2316602611
dmourati

Antworten:

22

Während eine zip-Datei tatsächlich ein Containerformat ist, gibt es keinen Grund, warum sie nicht aus einer Pipe (stdin) gelesen werden kann, wenn die Datei leicht genug in den Speicher passt. Hier ist ein Python-Skript, das eine Zip-Datei als Standardeingabe verwendet und den Inhalt in das aktuelle Verzeichnis oder in ein angegebenes Verzeichnis extrahiert, falls angegeben.

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)

Dieses Skript kann auf eine Zeile verkleinert und als Alias ​​erstellt werden.

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 '.')\""

Jetzt entpacke die Ausgabe von wget ganz einfach.

wget http://your.domain.com/your/file.zip -O - | unzip-stdin target_dir
Jason R. Coombs
quelle
1
Du und Python Rock !!!
Farid Nouri Neshat
3
Netter Einzeiler und +1 für die Erwähnung, dass die Datei in den Speicher passen muss. (Leider ist es aufgrund der Dateiformatstruktur nicht möglich, eine pkzip-Datei zu entpacken.)
lxgr
2
Denken Sie daran, dies puffert alles in Erinnerung, bevor Sie extrahieren
William Casarin
1
Es gibt keinen Grund, warum es nicht als Stream gelesen werden kann, wenn die Datei leicht genug in den Speicher passt und nicht wirklich genau ist. Der Grund, warum Sie gezwungen sind, das gesamte Zip-Archiv im Speicher zu puffern, bevor Sie den Inhalt extrahieren, liegt insbesondere darin, dass es nicht als Stream gelesen werden kann. Natürlich kann es trotzdem nützlich sein, das ZIP-Archiv nicht in eine Datei zu schreiben.
Håkan Lindqvist
Dies ist kein Stream, Sie lesen die gesamte Datei im Speicher mithilfe der .read()Methode
Romuald Brunet
17

Es ist unwahrscheinlich, dass dies so funktioniert, wie Sie es erwarten. Zip ist nicht nur ein Komprimierungsformat, sondern auch ein Containerformat. Es fasst die Jobs von tar und gzip.bzip2 zu einem zusammen. Wenn Ihre Zip-Datei jedoch nur eine einzige enthält, können Sie mit unzip -p die Dateien nach stdout extrahieren. Wenn Sie mehr als eine Datei haben, können Sie nicht feststellen, wo sie beginnen und enden.

Was das Lesen von stdin betrifft, enthält die Manpage zum Entpacken diesen Satz:

Von der Standardeingabe gelesene Archive werden noch nicht unterstützt, außer mit funzip (und dann kann nur das erste Mitglied des Archivs extrahiert werden).

Vielleicht hast du etwas Glück mit Funzip.

David Pashley
quelle
Wenn zip mehrere Dateien enthält, kann -p eine einzelne Datei mit dem Dateinamen als Parameter ausgeben: unzip -p temp.zip file-inside-zip
Taavi Ilves
7

Sie möchten, dass unzipeine ZIP-Datei nicht als Argument, sondern als Standardeingabe verwendet wird. Dies ist in der Regel leicht gestützt durch gzipund tarArt von Werkzeugen mit einem -Argument. Der Standard unziptut dies jedoch nicht (unterstützt jedoch die Extraktion in ein Rohr). Es ist jedoch nicht alles verloren ...

Schauen Sie sich die Funzip- Handbuchseite an.

funzip ohne Dateiargument fungiert als Filter. Das heißt, es wird davon ausgegangen, dass ein ZIP-Archiv (oder eine gzip-Datei) in die Standardeingabe geleitet wird, und das erste Mitglied wird aus dem Archiv in stdout extrahiert. Wenn stdin von einem tty-Gerät stammt, geht funzip davon aus, dass dies kein Stream von (binären) komprimierten Daten sein kann und zeigt stattdessen einen kurzen Hilfetext an. Wenn es ein Dateiargument gibt, wird die Eingabe von der angegebenen Datei anstelle von stdin gelesen.

Angesichts der Beschränkung der Einzelelementextraktion ist funzip in Verbindung mit einem sekundären Archivierungsprogramm wie tar (1) am nützlichsten. Der folgende Abschnitt enthält ein Beispiel, das diese Verwendung im Fall von Festplatten-Backups auf Band veranschaulicht.

Dies passt gut zu der Vorstellung, dass die meisten Linux-Archive normalerweise TAR'ed und dann in gewisser Weise ZIPped sind (gzip, bzip, et al.). Dies funktioniert für Sie, wenn Sie eine haben tar.ZIP.


Es ist erwähnenswert, dass funzipvon Info-ZIP-Originalautor Mark Adler geschrieben. Er schreibt in der Funzip-Manpage:

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

Es wird jedoch kein solches Update angezeigt. Ich vermute, dass Mark dies für unnötig hielt, da andere Archivierungsmethoden mit TAR problemlos funktionierten.

nik
quelle
Nur ein Kommentar; Manche möchten Python oder eine andere Sprache als Option zum Entpacken. Ein Paradebeispiel ist Heroku, das weder tar noch unzip enthält. Ein Workaround ist die Verwendung von jar durch die Installation von Java, was erlaubt ist.
Nick
Weitere Informationen zu Einschränkungen von funzip und ähnlichen Tools (die insbesondere nur das erste Mitglied eines Archivs anzeigen können
Joshua Goldberg
6

Ich verwende gerne curl, da es standardmäßig installiert ist (das -Lwird für häufig auftretende Weiterleitungen benötigt):

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

Ist bsdtarjedoch nicht standardmäßig installiert und ich konnte nicht funzipan die Arbeit gehen.

Todd Partridge
quelle
Funktioniert auch gut mit mehreren Dateien
jonnor
5

Dies ist eine Wiederholung meiner Antwort auf eine ähnliche Frage:

Das ZIP-Dateiformat enthält ein Verzeichnis (Index) am Ende des Archivs. In diesem Verzeichnis steht, wo sich innerhalb des Archivs jede Datei befindet und ermöglicht so einen schnellen, zufälligen Zugriff, ohne das gesamte Archiv zu lesen.

Dies scheint ein Problem zu sein, wenn versucht wird, ein ZIP-Archiv über eine Pipe zu lesen, da auf den Index erst ganz am Ende zugegriffen wird und daher einzelne Mitglieder erst dann korrekt extrahiert werden können, wenn die Datei vollständig gelesen wurde und nicht mehr verfügbar ist . Als solches erscheint es nicht überraschend, dass die meisten ZIP-Dekomprimierer einfach versagen, wenn das Archiv über eine Pipe geliefert wird.

Das Verzeichnis am Ende des Archivs ist nicht der einzige Ort, an dem Datei-Metainformationen im Archiv gespeichert werden. Darüber hinaus enthalten einzelne Einträge diese Informationen aus Redundanzgründen auch in einem lokalen Dateikopf.

Obwohl nicht jeder ZIP-Dekomprimierer lokale Dateiheader verwendet, wenn der Index nicht verfügbar ist, können und werden die Frontends tar und cpio für libarchive (auch bekannt als bsdtar und bsdcpio) beim Durchlesen einer Pipe verwendet. Dies bedeutet, dass Folgendes möglich ist:

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

Mit Info-Zip, der am häufigsten verwendeten OSS-Implementierung, ist dies nicht möglich. Noch wichtiger ist jedoch, dass dies aufgrund der Konstrukte von ZIP-Archiven nicht empfohlen wird.

Wenn Sie das Format ändern können, sollten Sie stattdessen tar (1) verwenden. Es ist ziemlich zufrieden mit der gestreamten Eingabe / Ausgabe und erwartet diese standardmäßig.

Außerdem können Sie häufig feststellen, ob Anwendungen gestreamte Ein- / Ausgaben erwarten, indem Sie "-" für einen Dateinamen angeben. Wie Sie sich vorstellen können, behandelt Info-Zip dies nicht als gültiges Argument.

Dan Carley
quelle
4

In zsh können Sie Folgendes tun:

unzip =( curl http://example.com/someZipFile.zip )
Ian Robertson
quelle
3

Das einfachste gängige Dienstprogramm, das hierfür zur Verfügung steht jar, setzt voraus, dass STDIN verwendet wird, wenn Sie keine Datei-Argumente übergeben. Es werden auch Argumente verwendet, die dem tarProgramm für Operationen ähneln .

zB den Inhalt eines Archivs auflisten

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

Java ist zwar nicht immer installiert, aber auf den Rechnern, auf denen es installiert ist, jarist dies definitiv die bequemste Methode.

Adrian
quelle
3

Repost meiner Antwort :

BusyBox's unzipkönnen stdin nehmen und alle Dateien extrahieren.

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

Der Bindestrich danach unzipist stdin als Eingabe zu verwenden.

Du kannst sogar,

cat file.zip | busybox unzip -

Aber das ist einfach überflüssig unzip file.zip.

Wenn Ihre Distribution standardmäßig BusyBox verwendet (z. B. Alpine), starten Sie einfach unzip -.

Saftever
quelle
1

Eigentlich brauchte ich etwas komplexeres - extrahiere eine bestimmte Datei, wenn sie existiert. Die Schwierigkeit besteht darin, dass der Eingabedateistream möglicherweise keine Zip-Datei ist. In diesem Fall musste er über die Pipe fortgesetzt werden. Hier ist meine Lösung (hauptsächlich dank Jason R. Coombs Lösung)

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

Ich habe dies als Datei mit dem Namen "effpoptp" (kein einfacher Name) im Ordner "/ bin" auf meinem Computer gespeichert.

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

Der Zweck ist die Versionskontrolle von MySQL Workbench-Dateien, wobei die Datei die XML-Datei sein kann, die als Workbench-Datei bezeichnet wird, oder die vollständige Workbench-Datei.

SEoF
quelle