解压缩通过管道飞入的文件


39

我可以使解压缩或任何类似程序在标准输出上工作吗?情况是我正在下载一个zip文件,该文件应该是即时解压缩的。

相关问题:如何将下载的文件通过管道传送到bash中的标准输出?


这似乎应该可行,但是如果zip仅包含一个文件,则似乎只能提取一个zip并将其通过管道传递给另一个命令。我想从多文件zip中提取特定文件。代替管道,我切换为链接多个命令'unzip file.zip / path / file && dostuff / path / file && rm -rf / path'虽然没有回答原始问题,并导致创建了临时文件,但它满足了我的要求需要。
Stan Kurdziel

看看pigz。我们在管道中使用它。 andrew.tumblr.com/post/2316602611
dmourati

Answers:


22

尽管zip文件实际上是一种容器格式,但是如果该文件足够容易地装入内存,则没有理由无法从管道(stdin)中读取该文件。这是一个Python脚本,它将zip文件作为标准输入,并将内容提取到当前目录或指定的目录(如果已指定)。

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)

该脚本可以缩小为一行,并作为别名创建。

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

现在,轻松解压缩wget的输出。

wget http://your.domain.com/your/file.zip -O - | unzip-stdin target_dir

1
您和python摇滚!!!
Farid Nouri Neshat

3
不错的单线,+ 1表示文件必须适合内存。(由于文件格式结构,不幸的是无法解压缩pkzip文件)。
lxgr 2012年

2
请记住,这会在提取之前缓冲所有内存
William Casarin 2014年

1
如果文件足够容易地装入内存,没有理由不能将其作为流读取,这并不是很准确。之所以必须在提取内容之前将整个zip存档缓冲在内存中,是因为无法将其作为流读取。当然,避免将zip存档写入文件仍然很有用。
哈坎·林奎斯特

不是流,您正在使用.read()方法
Romuald Brunet

17

这不太可能按您的预期工作。Zip不仅是压缩格式,而且是容器格式。它将tar和gzip.bzip2的作业汇总到一个。话虽如此,如果您的zip文件只有一个文件,则可以使用unzip -p将文件提取到stdout。如果您有多个文件,则无法告诉他们文件的开始和停止位置。

至于从stdin读取的内容,解压缩手册页包含以下语句:

从标准输入中读取的存档,除funzip以外,尚不支持(然后只能提取存档的第一个成员)。

您可能对funzip感到满意。


如果zip中包含多个文件,则-p可以使用文件名作为参数来打印出单个文件:unzip -p temp.zip file-inside-zip
Taavi Ilves,

7

您想要做的是,unzip在其标准输入上获取一个ZIPP文件,而不是将其作为参数。这通常是很容易支持gziptar样带工具-的说法。但是该标准unzip并没有做到这一点(尽管它确实支持提取到管道)。但是,一切并没有丢失...

查看funzip手册页。

没有文件参数的funzip充当过滤器;也就是说,假定已将ZIP归档文件(或gzip的文件)通过管道传输到标准输入中,并且将从归档文件中提取第一个成员到stdout。当stdin来自tty设备时,funzip假定它不能是(二进制)压缩数据流,而是显示简短的帮助文本。如果有文件参数,则从指定的文件而不是从stdin中读取输入。

考虑到单成员提取的限制,funzip与辅助归档程序(例如tar(1))结合使用最为有用。以下部分包括一个示例,说明在将磁盘备份到磁带的情况下的用法。

这与大多数linux归档文件通常经过TAR处理,然后以某种方式压缩(gzip,bzip等)的想法非常吻合。如果您有,这将为您工作tar.ZIP


值得注意的funzip是,由Info-ZIP的原始作者Mark Adler撰写。他在funzip手册页中写道,

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

但是,没有看到这样的更新。我怀疑Mark认为没有必要,因为其他归档方法可以轻松地与TAR一起使用。


只是一个评论;有些人希望使用python或任何语言来解压缩。一个很好的例子是Heroku,它的系统中不包含tar或unzip。解决方法是通过安装允许的Java使用jar。
尼克

在此答案中,还有更多关于处理funzip和类似工具(特别是仅能显示档案的第一位成员)的限制的信息:unix.stackexchange.com/a/211286/77539
Joshua Goldberg,

6

我喜欢使用curl,因为它是默认安装的(-L通常会发生重定向):

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

但是,bsdtar默认情况下未安装,因此无法funzip正常工作。


也可以很好地处理多个文件
jonnor

5

这是对类似问题的回答的转贴:

ZIP文件格式在存档末尾包含目录(索引)。该目录指出每个文件在档案中的位置,因此可以快速,随机地访问,而无需读取整个档案。

尝试通过管道读取ZIP归档文件时,这似乎造成了问题,因为直到最后才访问索引,因此只有在文件被完全读取并且不再可用之后,才能正确提取单个成员。 。因此,当通过管道提供归档文件时,大多数ZIP解压缩器只会失败就显得不足为奇了。

存档末尾的目录不是文件元信息存储在存档中的唯一位置。另外,出于冗余目的,各个条目还将此信息包含在本地文件头中。

尽管当索引不可用时,并不是每个ZIP解压缩器都将使用本地文件头,但是在通过管道读取时,libarchive(又名bsdtar和bsdcpio)的tar和cpio前端可以并且会这样做,这意味着可以进行以下操作:

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

4

Info-Zip是最常见的OSS实施,这是不可能的。不过,更重要的是,由于ZIP存档的构造,因此不建议使用。

如果可以更改格式,则可以考虑使用tar(1)。对流输入/输出感到非常满意,并且实际上,默认情况下期望它。

另外,您通常可以通过为文件名指定“-”来判断应用程序是否期望流输入/输出。您可以想象,Info-Zip不会将此视为有效参数。


4

在zsh中,您可以执行以下操作:

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

3

可以执行此操作的最简单的通用实用程序是jar,如果没有传递文件args,它将假定正在使用STDIN。它还采用与tar程序类似的参数进行操作。

例如列出档案的内容

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

尽管并不总是安装Java,但jar绝对是在Java计算机上安装Java 的最便捷方法。


3

转贴我的答案

BusyBox unzip可以使用stdin并提取所有文件。

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

后面的破折号unzip是使用stdin作为输入。

你甚至可以

cat file.zip | busybox unzip -

但这只是多余的unzip file.zip

如果您的发行版默认使用BusyBox(例如Alpine),请运行unzip -


1

实际上,我需要一些更复杂的东西-如果存在特定文件,则将其解压缩。困难在于,输入文件流可能不是zip文件,在这种情况下,我需要它继续通过管道。这是我的解决方案(主要感谢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)"

我将其保存为机器上“ / bin”文件夹中名为“ effpoptp”(不是简单名称)的文件,因此测试如下:

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

目的是对MySQL Workbench文件进行版本控制,其中该文件可以是名为工作台文件的xml文件,也可以是完整的工作台文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.