Могу ли я заставить unzip или другие подобные программы работать на стандартном выводе? Ситуация такова, что я скачиваю 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 для извлечения файлов в стандартный вывод. Если у вас несколько файлов, вы не сможете определить, где они начинаются и где заканчиваются.
Что касается чтения из стандартного ввода, на странице руководства по распаковке есть это предложение:
Архивы, считываемые со стандартного ввода, пока не поддерживаются, за исключением funzip (и тогда можно извлечь только первый член архива).
Возможно, вам повезет с funzip.
Что ты хочешь сделать, так это сделать unzip
взять файл в формате ZIP на стандартный ввод, а не в качестве аргумента. Обычно это легко поддерживается gzip
и tar
вид инструментов с -
аргумент. Но стандарт unzip
этого не делает (хотя и поддерживает извлечение в канал). Однако еще не все потеряно ...
смотреть на funzip страница руководства.
funzip без аргумента файла действует как фильтр; то есть предполагается, что ZIP-архив (или файл gzip'd) передается по конвейеру на стандартный ввод, и извлекает первый член из архива в стандартный вывод. Когда stdin поступает с tty-устройства, funzip предполагает, что это не может быть поток (двоичных) сжатых данных, и вместо этого показывает короткий текст справки. Если есть аргумент файла, то ввод считывается из указанного файла, а не из стандартного ввода.
Учитывая ограничение на извлечение одного элемента, funzip наиболее полезен в сочетании с программой вторичного архивирования, такой как tar (1). В следующем разделе приведен пример, иллюстрирующий это использование в случае резервного копирования диска на ленту.
Это хорошо согласуется с идеей, что большинство архивов Linux обычно архивируются в TAR, а затем каким-то образом архивируются (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-
Это невозможно с Info-Zip, который является наиболее распространенной реализацией OSS. Что еще более важно, это не рекомендуется из-за конструкции ZIP-архивов.
Если вы хотите изменить формат, рассмотрите возможность использования tar (1). Он вполне доволен потоковым вводом / выводом и, по сути, ожидает его по умолчанию.
Кроме того, часто можно определить, ожидают ли приложения потокового ввода / вывода, указав «-» в имени файла. Info-Zip, как вы понимаете, не рассматривает это как веский аргумент.
В zsh вы можете делать следующее:
unzip =( curl http://example.com/someZipFile.zip )
Самая простая доступная утилита, которая сделает это, - jar
, который будет предполагать, что используется STDIN, если вы не передадите ему аргументы файла. Он также принимает аргументы, аналогичные tar
программа для операций.
например перечислить содержимое архива
curl https://my.example.com/file.zip | jar t
Хотя Java не всегда устанавливается, на тех машинах, где она установлена, jar
определенно самый удобный способ сделать это.
Репост мой ответ:
BusyBox's 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 -
.
Мне действительно нужно было что-то посложнее - извлечь конкретный файл, если он существует. Сложность в том, что поток входного файла может не быть 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-файлом, названным как файл workbench, или полным файлом workbench.