Décompression des fichiers qui arrivent par un tuyau

40

Puis-je faire en sorte qu'unzip ou un programme similaire fonctionne sur la sortie standard? La situation est que je télécharge un fichier zip, qui est censé être décompressé à la volée.

Problème lié: comment diriger un fichier téléchargé vers une sortie standard dans bash?

Alex
la source
Cela semblait être faisable, mais il semble qu'il ne soit possible d'extraire un zip et de diriger le fichier vers une autre commande que si le zip ne contient qu'un seul fichier. Je voulais extraire un fichier spécifique d'un zip multi-fichier. Au lieu de la tuyauterie, j’ai décidé d’enchaîner plusieurs commandes: décompressez fichier.zip / chemin / fichier && dostuff / chemin / fichier && rm-rf / chemin '. avoir besoin.
Stan Kurdziel
Découvrez Pigz. Nous l'utilisons dans un tuyau. andrew.tumblr.com/post/2316602611
dmourati

Réponses:

22

Bien qu'un fichier zip soit en fait un format conteneur, il n'y a aucune raison pour qu'il ne puisse pas être lu à partir d'un tube (stdin) si le fichier peut tenir dans la mémoire assez facilement. Voici un script Python qui prend un fichier zip en entrée standard et en extrait le contenu dans le répertoire actuel ou dans un répertoire spécifié, le cas échéant.

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)

Ce script peut être réduit à une ligne et créé comme un 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 '.')\""

Décompressez maintenant facilement la sortie de wget.

wget http://your.domain.com/your/file.zip -O - | unzip-stdin target_dir
Jason R. Coombs
la source
1
Toi et Python Rock !!!
Farid Nouri Neshat
4
Nice one-liner, et +1 pour mentionner que le fichier doit tenir dans la mémoire. (Il n’existe malheureusement aucun moyen de décompresser un fichier pkzip en raison de la structure de format de fichier).
Lxgr
2
gardez à l'esprit que tout est mis en mémoire tampon avant l'extraction
William Casarin
1
il n'y a aucune raison pour laquelle il ne peut pas être lu comme un flux si le fichier peut facilement entrer dans la mémoire n'est pas assez précis. La raison pour laquelle vous êtes obligé de mettre en mémoire tampon la totalité de l'archive zip avant d'extraire le contenu est spécifiquement due au fait qu'elle ne peut pas être lue sous forme de flux. Bien sûr, il peut toujours être utile d'éviter d'écrire l'archive zip dans un fichier.
Håkan Lindqvist
Ce n'est pas un flux, vous lisez le fichier en entier en mémoire en utilisant la .read()méthode
Romuald Brunet
18

Il est peu probable que cela fonctionne comme vous le souhaitez. Zip n'est pas simplement un format de compression, mais aussi un format de conteneur. Il regroupe les travaux de tar et de gzip.bzip2. Cela dit, si votre zip ne contient qu'un seul fichier, vous pouvez utiliser unzip -p pour extraire les fichiers sur la sortie standard. Si vous avez plus d'un fichier, vous n'avez aucun moyen de dire où ils commencent et s'arrêtent.

Pour ce qui est de stdin, la page de manuel unzip contient la phrase suivante:

Les archives lues à partir d'une entrée standard ne sont pas encore supportées, à l'exception de funzip (seul le premier membre de l'archive peut être extrait).

Vous pourriez avoir un peu de chance avec funzip.

David Pashley
la source
Si zip contient plusieurs fichiers, -p peut imprimer un fichier unique en utilisant le nom de fichier comme paramètre: unzip -p temp.zip file-inside-zip
Taavi Ilves
7

Ce que vous voulez faire est de faire unzipprendre un fichier ZIPped sur son entrée standard plutôt qu’en argument. Cela est généralement facilement pris en charge par gzipet tartype d'outils avec un -argument. Mais la norme unzipne le fait pas (cependant, elle supporte l'extraction vers un tuyau). Cependant, tout n'est pas perdu...

Regardez la page de manuel de funzip .

funzip sans argument de fichier agit comme un filtre; c'est-à-dire qu'il suppose qu'une archive ZIP (ou un fichier gzip'd) est en cours de transmission dans l'entrée standard et qu'il extrait le premier membre de l'archive sur stdout. Si stdin provient d'un périphérique tty, funzip suppose qu'il ne peut s'agir d'un flux de données compressées (binaires) et affiche plutôt un texte d'aide abrégé. S'il existe un argument de fichier, l'entrée est lue à partir du fichier spécifié au lieu de stdin.

Étant donné les limites relatives à l'extraction d'un seul membre, funzip est particulièrement utile avec un programme d'archivage secondaire tel que tar (1). La section suivante comprend un exemple illustrant cette utilisation dans le cas des sauvegardes sur disque sur bande.

Cela va bien avec l'idée que la plupart des archives Linux sont habituellement TAR'ed, puis ZIPped d'une manière ou d'une autre (gzip, bzip, et autres). Cela fonctionnera pour vous si vous avez un tar.ZIP.


Il est à noter que funzipc'est écrit par l'auteur original d'Info-ZIP, Mark Adler. Il écrit dans la page de manuel funzip,

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

Cependant, aucune mise à jour de ce type n'est visible. Je soupçonne que Mark l’a trouvé inutile étant donné que d’autres méthodes d’archivage fonctionnent facilement avec TAR.

nik
la source
Juste un commentaire; Certaines personnes voudraient décompresser en python ou dans n’importe quel langage. Heroku en est un excellent exemple. Il ne comprend ni tar ni unzip sur son système. Une solution consiste à utiliser jar en installant Java, ce qui est autorisé.
Nick
Il y a plus d'informations sur la gestion des limitations de funzip et d'outils similaires (en particulier, seule la capacité de montrer le premier membre d'une archive) est incluse
Joshua Goldberg
6

J'aime utiliser curl car il est installé par défaut ( -Lc'est nécessaire pour les redirections qui se produisent souvent):

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

Cependant, bsdtarn’est pas installé par défaut et je n’ai pas pu me mettre funzipau travail.

Todd Partridge
la source
Fonctionne
5

Voici un extrait de ma réponse à une question similaire:

Le format de fichier ZIP comprend un répertoire (index) à la fin de l'archive. Ce répertoire indique où, dans l’archive, se trouve chaque fichier et permet ainsi un accès rapide et aléatoire, sans lire l’archive complète.

Cela semblerait poser un problème lors de la tentative de lecture d'une archive ZIP par un canal, dans la mesure où l'index n'est accessible qu'à la toute fin et que les membres individuels ne peuvent donc pas être extraits correctement avant la lecture complète du fichier et sa non disponibilité. . En tant que tel, il ne semble pas surprenant que la plupart des décompresseurs ZIP échouent simplement lorsque l'archive est fournie via un tube.

Le répertoire à la fin de l'archive n'est pas le seul emplacement où les méta-informations de fichier sont stockées dans l'archive. De plus, les entrées individuelles incluent également ces informations dans un en-tête de fichier local, à des fins de redondance.

Bien que tous les décompresseurs ZIP n'utilisent pas les en-têtes de fichiers locaux lorsque l'index n'est pas disponible, les versions de tar et cpio se terminant par libarchive (alias bsdtar et bsdcpio) peuvent et le feront lors de la lecture via un canal, ce qui signifie que:

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

Ce n'est pas possible avec Info-Zip, qui est l'implémentation OSS la plus courante. Plus important encore, ce n'est pas recommandé en raison de la structure des archives ZIP.

Si un changement de format est viable pour vous, envisagez plutôt d'utiliser tar (1). Il est assez satisfait des entrées / sorties en flux et l’attend en fait par défaut.

De plus, vous pouvez souvent savoir si les applications attendent des entrées / sorties en streaming en spécifiant "-" pour un nom de fichier. Comme vous pouvez l'imaginer, Info-Zip ne considère pas cela comme un argument valable.

Dan Carley
la source
4

En zsh, vous pouvez effectuer les opérations suivantes:

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

L'utilitaire commun le plus simple disponible à cet effet est jar, ce qui présume que STDIN est utilisé si vous ne lui transmettez pas d'argument de fichier. Il faut également des arguments similaires au tarprogramme pour les opérations.

par exemple, lister le contenu d'une archive

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

Bien que Java ne soit pas toujours installé, jarla méthode la plus pratique est certainement celle qui s’y trouve.

Adrian
la source
3

Repost de ma réponse :

BusyBox unzippeut prendre stdin et extraire tous les fichiers.

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

Le tiret suivant unzipconsiste à utiliser stdin en tant qu'entrée.

Vous pouvez même,

cat file.zip | busybox unzip -

Mais c'est juste redondant de unzip file.zip.

Si votre distribution utilise BusyBox par défaut (par exemple, Alpine), lancez simplement unzip -.

Saftever
la source
1

En fait, j'avais besoin de quelque chose d'un peu plus complexe - extraire un fichier spécifique s'il existe. La difficulté étant que le flux de fichier d'entrée ne soit peut-être pas un fichier zip, et dans ce cas, je l'avais besoin pour continuer à travers le tuyau. Voici ma solution (principalement grâce à la solution 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)"

J'ai sauvegardé ceci en tant que fichier nommé "effpoptp" (pas un nom simple) dans le dossier "/ bin" sur ma machine, donc le tester ressemble à ça:

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

Le but est de contrôler la version des fichiers MySQL Workbench, le fichier pouvant être le fichier xml nommé comme fichier de plan de travail ou le fichier de plan de travail complet.

SEOF
la source