it-swarm-ru.tech

Распаковка файлов, которые летят через трубу

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

Связанная проблема: Как передать загруженный файл в стандартный вывод в bash?

43
Alex

Хотя 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
22
Jason R. Coombs

Это вряд ли сработает так, как вы ожидаете. Zip - это не просто формат сжатия, но и формат контейнера. Он объединяет задания tar и gzip.bzip2 в одно целое. Сказав это, если ваш Zip имеет один файл, вы можете использовать unzip -p для распаковки файлов в stdout. Если у вас есть более одного файла, вы не сможете сказать, где они начинаются и останавливаются.

Что касается чтения из stdin, на странице руководства по разархивированию есть следующее предложение:

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

Возможно, вам повезет с funzip.

18
David Pashley

Что вы хотите сделать, так это заставить unzip принимать ZIP-файл на его стандартный ввод, а не в качестве аргумента. Обычно это легко поддерживается инструментами gzip и ​​tar с - аргумент. Но стандарт unzip этого не делает (хотя поддерживает извлечение в канал). Однако еще не все потеряно ...

Посмотрите на funzip страницу руководства.

funzip без аргумента файла действует как фильтр; то есть предполагается, что Zip-архив (или файл gzip) передается в стандартный ввод, и он извлекает первого члена из архива в стандартный вывод. Когда stdin приходит с устройства tty, funzip предполагает, что это не может быть поток (двоичных) сжатых данных, и вместо этого показывает краткий текст справки. Если есть аргумент файла, то входные данные читаются из указанного файла, а не из стандартного ввода.

Учитывая ограничение на извлечение из одного члена, funzip наиболее полезен в сочетании со вспомогательной программой-архиватором, такой как tar (1). В следующем разделе приведен пример, иллюстрирующий это использование в случае резервного копирования диска на ленту.

Это хорошо согласуется с идеей, что большинство Linux-архивов, как правило, TAR-файлы, а затем каким-то образом ZIP-архивы (gzip, bzip и др.). Это будет работать для вас, если у вас есть tar.Zip.


Стоит отметить, что funzip написано автором Info-Zip Марком Адлером. Он пишет на странице руководства funzip:

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

однако такого обновления не наблюдается. Я подозреваю, что Марк нашел это ненужным, так как другие методы архивации легко работали с TAR.

7
nik

Мне нравится использовать curl, потому что он установлен по умолчанию (-L необходим для редиректов, которые часто происходят):

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

Однако bsdtar не установлен по умолчанию, и я не смог заставить funzip работать.

7
Todd Partridge

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

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

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

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

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

wget -qO- http://example.org/file.Zip | bsdtar -xvf-
5
ruario

В zsh вы можете сделать следующее:

unzip =( curl http://example.com/someZipFile.Zip )
4
Ian Robertson

Самая простая доступная утилита, которая сделает это, это jar, которая будет предполагать, что используется STDIN, если вы передадите ей файл без аргументов. Он также принимает аргументы, аналогичные программе tar, для операций.

например перечислить содержимое архива

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

Хотя Java не всегда устанавливается, на тех машинах, где она установлена, jar, безусловно, является наиболее удобным способом сделать это.

4
Adrian

Это невозможно с Info-Zip, который является наиболее распространенной реализацией OSS. Что еще более важно, это не рекомендуется из-за конструкции архивов Zip.

Если вам необходимо изменить формат, рассмотрите возможность использования tar (1). Он вполне доволен потоковым вводом/выводом и, по сути, ожидает его по умолчанию.

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

4
Dan Carley

Репост мой ответ :

unzip BusyBox может взять 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 -.

3
Saftever

Мне действительно нужно что-то более сложное - извлечь конкретный файл, если он существует. Сложность в том, что поток входного файла не может быть файлом Zip, и в этом случае мне нужно было продолжить через канал. Вот мое решение (в основном благодаря решению Джейсона Р. Кумбса)

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

Я сохранил это как файл с именем "effpoptp" (не простое имя) в папке "/ bin" на моей машине, поэтому тестирование это выглядит так:

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

Цель состоит в том, чтобы управлять версиями файлов MySQL Workbench, где файл может быть файлом XML, названным как файл рабочей среды, или полным файлом рабочей среды.

1
SEoF