Розпакуйте файли, які летять через трубу


39

Чи можу я змусити розпакувати або будь-які подібні програми працювати на стандартному виході? Ситуація полягає в тому, що я завантажую поштовий файл, який повинен бути розпакований на льоту.

Пов’язане питання: Як передавати завантажений файл на стандартний вихід у bash?


Це здавалося, що це повинно бути виконаним, але схоже, що витяг поштового індексу та передавання файлу в іншу команду можливий лише в тому випадку, якщо в zip є лише один файл. Я хотів отримати певний файл із багатофайлового блискавки. Замість трубопроводів я перейшов до прив’язки декількох команд 'unzip file.zip / path / file && dostuff / path / file && rm -rf / path' Хоча не відповідав на початкове запитання і в результаті створювалися тимчасові файли, це задовольнило мою потреба.
Stan Kurdziel

Перевірте свиню. Ми використовуємо його в трубі. andrew.tumblr.com/post/2316602611
dmourati

Відповіді:


22

Хоча 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

1
Ви і пітон рок !!!
Фарид Нурі Нешат

3
Хороший однолінійний додаток та +1 для згадки про те, що файл повинен вміститися в пам'яті. (На жаль, немає можливості розпакувати файл pkzip через структуру файлового формату).
lxgr

2
майте на увазі, це буферизує все, що запам'ятовується, перш ніж витягувати
Вільям Касарін

1
немає жодної причини, чому він не може бути прочитаний як потік, якщо файл може вміститися в пам'яті досить легко, насправді не є точним. Причина, через яку ви змушені буферувати весь zip-архів у пам'яті перед вилученням вмісту, полягає саме в тому, що він не може бути прочитаний як потік. Звичайно, це все ще може бути корисно, щоб уникнути запису zip-архіву у файл.
Хокан Ліндквіст

Це не потік, ви читаєте весь файл у пам’яті, використовуючи .read()метод
Romuald Brunet

17

Це навряд чи вийде, як ви очікуєте. Zip - це не лише формат стиснення, а й формат контейнера. Він зводить завдання як tar, так і gzip.bzip2 в одну. Сказавши, що якщо ваш поштовий індекс має один файл, ви можете використовувати unzip -p для витягування файлів у stdout. Якщо у вас є більше одного файлу, ви не можете сказати, де вони починаються та зупиняються.

Щодо читання з stdin, на сторінці unzip man є таке речення:

Архів, прочитаний зі стандартного введення, ще не підтримується, за винятком функції funzip (і тоді може бути вилучений лише перший член архіву).

Можливо, вам пощастить з funzip.


Якщо всередині zip є декілька файлів, то -p може роздрукувати один файл, використовуючи ім'я файлу як параметр: unzip -p temp.zip file-inside-zip
Taavi Ilves

7

Що ви хочете зробити, це зробити, щоб unzipвзяти ZIPped файл на його стандартному вході, а не як аргумент. Це, як правило , легко підтримується gzipі tarвид інструментів з -аргументом. Але стандарт unzipцього не робить (хоча, він підтримує витяг до труби). Однак все не втрачено ...

Подивіться сторінку посібника з функцією funzip .

funzip без аргументу файлу виконує функції фільтра; тобто передбачається, що ZIP-архів (або файл gzip'd) передається на стандартний вхід, і він витягує першого члена з архіву до stdout. Коли stdin надходить із пристрою tty, funzip припускає, що це не може бути потік (двійкових) стислих даних і натомість показує короткий довідковий текст. Якщо є аргумент файлу, то введення зчитується із зазначеного файлу замість stdin.

Враховуючи обмеження на одночасне вилучення, funzip є найбільш корисним у поєднанні з додатковою програмою архівації, такою як tar (1). Наступний розділ містить приклад, що ілюструє це використання у випадку резервного копіювання диска на стрічку.

Це добре поєднується з ідеєю, що більшість архівів Linux зазвичай є TAR'ed, а потім якимось чином ZIPped (gzip, bzip та ін.). Це буде працювати для вас, якщо у вас є tar.ZIP.


Варто зазначити, що funzipнаписаний оригінальним автором Info-ZIP Марком Адлером. Він пише на сторінці manzip man,

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

однак такого оновлення навколо не спостерігається. Я підозрюю, що Марк вважав це непотрібним, оскільки інші методи архівації легко працювали з TAR.


Просто коментар; деякі люди хочуть, щоб розгорнути пітон або будь-яку мову. Прекрасний приклад - Heroku, який не включає смоли або розпакування у своїй системі. Робота полягає в тому, щоб використовувати jar, встановивши дозволений Java.
Нік

Більше про розгляд обмежень функцій funzip та подібних інструментів (зокрема, лише в змозі показувати першого члена архіву) в цій відповіді: unix.stackexchange.com/a/211286/77539
Джошуа Голдберг

6

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

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

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


Також чудово працює з декількома файлами
jonnor

5

Це репост моєї відповіді на подібне запитання:

Формат ZIP-файлу містить каталог (покажчик) в кінці архіву. У цьому каталозі зазначено, де всередині архіву розташований кожен файл, що дозволяє швидко і випадково отримати доступ, не читаючи весь архів.

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

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

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

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

4

Це неможливо з Info-Zip, який є найбільш поширеною реалізацією OSS. Що ще важливіше, це не рекомендується через конструкції ZIP-архівів.

Якщо зміна формату вам життєздатна, тоді замість цього скористайтеся tar (1). Він цілком задоволений потоковим входом / виходом і насправді очікує цього за замовчуванням.

Крім того, ви часто можете дізнатися, чи очікують програми потокові введення / виведення, вказавши "-" ім'я файлу. Як ви можете уявити, Info-Zip не сприймає це як вагомий аргумент.



3

Найпростіша загальна доступна утиліта, яка це зробить, - це jar, припускаючи, що STDIN використовується, якщо ви не передаєте аргументи файлів. Також tarдля операцій потрібні аргументи, схожі на програму.

наприклад, перерахуйте вміст архіву

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

Хоча Java не завжди встановлюється, на тих машинах, де вона є, jar- це, безумовно, найзручніший спосіб зробити це.


3

Репост моєї відповіді :

BusyBox unzipможе приймати 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 -.


1

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.