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