Можно ли заставить распаковать или какие-нибудь похожие программы работать на стандартном выходе? Ситуация такова, что я загружаю Zip-файл, который должен быть распакован на лету.
Связанная проблема: Как передать загруженный файл в стандартный вывод в bash?
Хотя 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.
Что вы хотите сделать, так это заставить 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.
Мне нравится использовать 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-
В zsh вы можете сделать следующее:
unzip =( curl http://example.com/someZipFile.Zip )
Самая простая доступная утилита, которая сделает это, это jar
, которая будет предполагать, что используется STDIN, если вы передадите ей файл без аргументов. Он также принимает аргументы, аналогичные программе tar
, для операций.
например перечислить содержимое архива
curl https://my.example.com/file.Zip | jar t
Хотя Java не всегда устанавливается, на тех машинах, где она установлена, jar
, безусловно, является наиболее удобным способом сделать это.
Это невозможно с Info-Zip, который является наиболее распространенной реализацией OSS. Что еще более важно, это не рекомендуется из-за конструкции архивов Zip.
Если вам необходимо изменить формат, рассмотрите возможность использования tar (1). Он вполне доволен потоковым вводом/выводом и, по сути, ожидает его по умолчанию.
Кроме того, вы часто можете определить, ожидают ли приложения потокового ввода/вывода, указав "-" для имени файла. Info-Zip, как вы можете себе представить, не воспринимает это как веский аргумент.
Репост мой ответ :
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 -
.
Мне действительно нужно что-то более сложное - извлечь конкретный файл, если он существует. Сложность в том, что поток входного файла не может быть файлом 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, названным как файл рабочей среды, или полным файлом рабочей среды.