如何将 wget 的输出重定向为解压缩的输入?

And*_*sne 169 command-line io-redirection

我必须从这个链接下载一个文件。文件下载是一个 zip 文件,我必须将其解压缩到当前文件夹中。

通常,我会先下载它,然后运行 ​​unzip 命令。

$ wget http://www.vim.org/scripts/download_script.php?src_id=11834 -O temp.zip
$ unzip temp.zip
Run Code Online (Sandbox Code Playgroud)

但是这样,我需要执行两个命令,等待第一个执行完成后执行下一个,而且,我必须知道文件的名称temp.zip才能将其提供给unzip.

是否可以将输出重定向wgetunzip?就像是

$ unzip < `wget http://www.vim.org/scripts/download_script.php?src_id=11834`
Run Code Online (Sandbox Code Playgroud)

但它没有用。

bash wget http://www.vim.org/scripts/download_script.php?src_id=11834 -O temp.zip:: 不明确的重定向

此外,wget被执行了两次,并下载了两次文件。

tan*_*nte 128

您必须将文件下载到临时文件,因为(引用解压缩手册页):

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

只需将命令放在一起:

wget "http://www.vim.org/scripts/download_script.php?src_id=11834" -O temp.zip
unzip temp.zip
rm temp.zip
Run Code Online (Sandbox Code Playgroud)

但是为了使其更灵活,您可能应该将其放入脚本中,以便您节省一些输入,并确保您不会意外覆盖某些内容,您可以使用该mktemp命令为您的临时文件创建一个安全的文件名:

#!/bin/bash
TMPFILE=`mktemp`
PWD=`pwd`
wget "$1" -O $TMPFILE
unzip -d $PWD $TMPFILE
rm $TMPFILE
Run Code Online (Sandbox Code Playgroud)

  • @NextLocal `wget &amp;&amp; unzip` 只有在 wget 成功时才会运行解压缩。`wget; unzip` 无论如何都会运行 unzip,可能指向不存在的文件。 (11认同)
  • funzip 是我一直在寻找的答案。Terraform(出于某种原因)将它的二进制文件打包为 zip 存档中的单个文件,因此这对我来说是完美的。 (2认同)

小智 104

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

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

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

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

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

wget -qO- http://example.org/file.zip | bsdtar -xvf-
Run Code Online (Sandbox Code Playgroud)

  • 我这里有一个 `.zip` 文件,其中包含具有可执行权限的文件。当我下载并通过管道输入 `bsdtar` 时,exec 位会被丢弃。当我下载到磁盘并使用 `bsdtar` 或 `unzip` 解压缩时,exec 位得到尊重。 (3认同)
  • 这太棒了!我会注意到 tar 给了我一些关于未压缩数据大小错误(预期为 0)的警告,但文件本身似乎没有损坏。猜测这是由于缺乏索引。 (2认同)
  • @NathanBasanese:[这里](https://github.com/libarchive/libarchive/issues/1106#issuecomment-446219915) 是答案。简而言之:ZIP 存档有两个位置存储此类信息,这可能会不一致,并且取决于打开的文件 `bsdtar` 是否可查找,它使用一个位置或另一个位置。 (2认同)

小智 29

如果您安装了 JDK,则可以使用jar

wget -qO- http://example.org/file.zip | jar xvf /dev/stdin
Run Code Online (Sandbox Code Playgroud)

  • 您不需要提供文件参数,只需使用`| 罐子 xv` (12认同)
  • 我刚刚发现`jar` 不保留文件权限。否则很好的把戏。 (8认同)

小智 21

转贴我的回答

BusyBoxunzip可以使用标准输入并提取所有文件。

wget -qO- http://downloads.wordpress.org/plugin/akismet.2.5.3.zip | busybox unzip -
Run Code Online (Sandbox Code Playgroud)

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

你甚至可以,

cat file.zip | busybox unzip -
Run Code Online (Sandbox Code Playgroud)

但这只是多余的unzip file.zip

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


Bru*_*ger 20

我认为您甚至不想费心将 wget 的输出传输到解压缩中。

来自维基百科“ZIP(文件格式)”文章:

ZIP 文件通过位于文件末尾的中央目录来标识。

wget 必须在 unzip 执行任何工作之前完全完成下载,因此它们按顺序运行,而不是像人们想象的那样交织在一起。


ken*_*orb 17

正确的语法是:

$ unzip <(curl -sL https://www.winpcap.org/archive/1.0-docs.zip)
Run Code Online (Sandbox Code Playgroud)

但它不起作用,因为错误(Debian上的Info-ZIP):

lseek(3, 0, SEEK_SET)                   = -1 ESPIPE (Illegal seek)

Archive:  /dev/fd/63
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of /dev/fd/63 or
        /dev/fd/63.zip, and cannot find /dev/fd/63.ZIP, period.
Run Code Online (Sandbox Code Playgroud)

或在 BSD/OS X 上:

Trying to read large file (> 2 GiB) without large file support
Run Code Online (Sandbox Code Playgroud)

这是因为标准的 zip 工具主要使用lseek函数来设置文件末尾的偏移量以读取其中央目录记录的末尾。它位于存档结构的末尾,需要读取文件列表(请参阅:Zip 文件格式结构)。因此文件不能是 FIFO、管道、终端设备或任何其他动态文件,因为lseek函数无法定位输入对象。

因此,您有以下解决方法:

  • 使用不同类型的压缩(例如tar.gz),
  • 你必须使用两个单独的命令,
  • 使用替代工具(如其他答案中所建议),
  • 创建别名或函数以使用多个命令。