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

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

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

12 ответов

Хотя 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

BusyBox-х unzip может взять стандартный ввод и извлечь все файлы.

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

Черта после unzip это использовать стандартный ввод в качестве ввода.

Вы можете даже,

cat file.zip | busybox unzip -

Но это просто избыточно unzip file.zip,

Если ваш дистрибутив использует BusyBox по умолчанию (например, Alpine), просто запустите unzip -,

Что вы хотите сделать, это сделать 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.

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

например, список содержимого архива

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

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

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

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

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

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

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

Мне действительно нужно что-то более сложное - извлечь конкретный файл, если он существует. Сложность в том, что поток входного файла может быть не 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, названным как файл рабочей среды, или полным файлом рабочей среды.

Я написал скрипт Python (2.x) для потокового извлечения ZIP-архивов (который использует постоянный объем памяти независимо от размера ZIP-файла), вы можете получить его здесь: https://raw.githubusercontent . com/pts/unzip_scan/master/unzip_scan.py . Использование:cat file.zip | sh unzip_scan.py -.

Функция scan_zip реализует потоковый анализатор (и декомпрессор) для формата файлов ZIP (и Zip64), включая несколько расширений (так что он поддерживает файлы-члены размером более 4 ГиБ, а также извлекает время последнего изменения). Он использует zlib.decompressobj (часть стандартной библиотеки Python, тяжелая работа реализована на C) для фактической распаковки Flate.

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

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

Этот подход по-прежнему требует внесения изменений в локальную файловую систему (создание монтирования), но его можно использовать для разархивирования файлов при их потоковой передаче по сети.

Теоретически должно быть возможно реализовать нечто подобное, используя HTTP-запросы Range для выполнения дополнительных или выборочных операций с zip-архивом над zip-файлом, размещенным по HTTP.

Другие вопросы по тегам