Как перенаправить вывод wget как вход для распаковки?


131

Я должен скачать файл по этой ссылке . Загрузочный файл представляет собой zip-файл, который мне нужно будет распаковать в текущую папку.

Обычно я сначала загружаю его, затем запускаю команду unzip.

$ wget http://www.vim.org/scripts/download_script.php?src_id=11834 -O temp.zip
$ unzip temp.zip

Но, таким образом, мне нужно выполнить две команды, дождаться завершения первой, чтобы выполнить следующую, также я должен знать имя файла, temp.zipкоторому он будет передан unzip.

Можно ли перенаправить вывод wgetна unzip? Что-то вроде

$ unzip < `wget http://www.vim.org/scripts/download_script.php?src_id=11834`

Но это не сработало.

bash wget http://www.vim.org/scripts/download_script.php?src_id=11834 -O temp.zip:: неоднозначный редирект

Кроме того, wgetбыл выполнен дважды, и загрузил файл дважды.


В последнем примере, wget, вероятно, был выполнен дважды, потому что? это специальный символ в оболочке. Помещение URL в "" должно помочь.
p-static

Кажется, у этой темы есть решение. Хотя сам не пробовал. serverfault.com/questions/26474/...

Ответы:


96

Вы должны загрузить свои файлы во временный файл, потому что (цитируя распакованную man-страницу):

Архивы, считанные из стандартного ввода, пока не поддерживаются, за исключением funzip (и тогда может быть извлечен только первый элемент архива).

Просто соберите команды:

wget http://www.vim.org/scripts/download_script.php?src_id=11834 -O temp.zip; unzip temp.zip; rm temp.zip

Но для того, чтобы сделать его более гибким, вы, вероятно, должны поместить его в скрипт, чтобы сохранить некоторую типизацию и, чтобы убедиться, что вы случайно не перезаписали что-либо, вы можете использовать mktempкоманду для создания безопасного имени файла для вашего временного файла:

#!/bin/bash
TMPFILE=`mktemp`
PWD=`pwd`
wget "$1" -O $TMPFILE
unzip -d $PWD $TMPFILE
rm $TMPFILE

Является ли wget file.zip && unzip file.zipтакой же wget file.zip; unzip file.zipили один предпочтительным по сравнению с другим? Спасибо :)
Jaggedsoft

7
@NextLocal wget && unzipбудет запускать распаковку только в случае успеха wget. wget ; unzipв любом случае будет запускать распаковку, возможно, указывая на несуществующий файл.
Темото

funzip был ответом, который я искал. Terraform (по какой-то причине) упаковывает его в двоичный файл как один файл в zip-архиве, так что это идеально для меня.
Асфанд Кази

75

Это перепост моего ответа на похожий вопрос:

Формат файла ZIP включает в себя каталог (индекс) в конце архива. В этом каталоге указывается, где в архиве находится каждый файл, и, таким образом, обеспечивается быстрый произвольный доступ без чтения всего архива.

Это может создать проблему при попытке чтения ZIP-архива через канал, поскольку доступ к индексу не осуществляется до самого конца, и поэтому отдельные элементы не могут быть правильно извлечены до тех пор, пока файл не будет полностью прочитан и больше не доступен , Таким образом, неудивительно, что большинство декомпрессоров ZIP просто терпят неудачу, когда архив подается по каналу.

Каталог в конце архива - не единственное место, где метаинформация файла хранится в архиве. Кроме того, отдельные записи также включают эту информацию в локальный заголовок файла для целей резервирования.

Хотя не каждый ZIP-распаковщик будет использовать локальные заголовки файлов, когда индекс недоступен, внешние интерфейсы tar и cpio для libarchive (также известные как bsdtar и bsdcpio) могут и будут делать это при чтении через канал, что означает следующее:

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

1
Это отлично! Я хотел бы отметить, что tar дает мне несколько предупреждений о том, что несжатые данные имеют неправильный размер (ожидаемый 0), но сами файлы выглядят не поврежденными. Предположение об этом связано с отсутствием индекса.
Wyatt8740

1
У меня есть .zip-файл, который содержит файлы с разрешениями на выполнение. Когда я загружаю и загружаю bsdtar, исполняемые биты выбрасываются. Когда я загружаю на диск и извлекаю с помощью bsdtarили unzipзатем, исполняемые биты соблюдаются.
Голар Рамблар

//, @GolarRamblar, ты когда-нибудь узнавал почему?
Натан Басанезе

1
@NathanBasanese: вот ответ. Вкратце: ZIP-архив имеет два места, где он хранит такую ​​информацию, которая может быть противоречивой, и в зависимости от того, bsdtarоткрывается ли файл, можно искать или нет, он использует одно или другое место.
Голар Рамблар

20

Если у вас установлен JDK, вы можете использовать jar:

wget -qO- http://example.org/file.zip | jar xvf /dev/stdin

3
Я только что обнаружил, что jarне сохраняет права доступа к файлам. Хороший трюк в противном случае.
phunehehe

7
Вам не нужно | jar xv
указывать

15

Я не думаю, что вы даже хотите докучать о выводе wget в распаковку.

Из статьи в википедии "ZIP (формат файла)" :

ZIP-файл определяется наличием центрального каталога, расположенного в конце файла.

wget должен полностью завершить загрузку, прежде чем unzip сможет выполнить какую-либо работу, поэтому они запускаются последовательно, а не переплетаются, как можно подумать.


10

Правильный синтаксис будет:

$ unzip <(curl -sL https://www.winpcap.org/archive/1.0-docs.zip)

но это не сработает из-за ошибки ( Info-ZIP на Debian ):

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.

или на BSD / OS X:

Trying to read large file (> 2 GiB) without large file support

Это связано с тем, что стандартные zip-инструменты в основном используют lseekфункцию , чтобы установить смещение файла в конце для чтения его конца записи центрального каталога . Он расположен в конце структуры архива и необходим для чтения списка файлов (см .: Структура формата файла Zip ). Поэтому файл не может быть FIFO, каналом, оконечным устройством или любой другой динамикой, потому что входной объект не может быть позиционирован lseekфункцией.

Итак, у вас есть следующие обходные пути:

  • использовать различные виды сжатия (например tar.gz),
  • Вы должны использовать две отдельные команды,
  • использовать альтернативные инструменты (как предлагается в других ответах),
  • создать псевдоним или функцию для использования нескольких команд.

Я думаю, что это все еще может быть FIFO. Вам просто нужно будет продолжать чтение из FIFO до EOF (эффективно буферизуя весь FIFO в памяти или во временном файле). Полностью выполнимый, чтобы облегчить создание сценария, но не очень полезный.
Эван Кэрролл

8

Репост моего ответа :

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

Это работает для меня довольно хорошо:

tar xvf <(curl -sL http://www.vim.org/scripts/download_script.php?src_id=11834)

jar xvf <(curl -sL http://www.vim.org/scripts/download_script.php?src_id=11834)

wget -qO- http://www.vim.org/scripts/download_script.php?src_id=11834 | tar xvf -

wget -qO- http://www.vim.org/scripts/download_script.php?src_id=11834 | jar xvf -
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.