Як я можу фільтрувати вміст файлу дьогтю, створюючи ще один файл смоли в трубі?


13

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

Шукаєте щось на зразок:

tar -f some.tar.gz --subset subdir/ | ssh remote@system tar xvz

Також важливо, щоб основні атрибути (право власності, група, режим, mtime) в цьому архіві tar-файлу зберігалися. Що щодо інших атрибутів у файлі tar, таких як розширені ключові слова ?

Бонусні бали за рішення, що дозволяє уникнути використання тимчасового каталогу, якщо цей піддір містить величезні файли.

Відповіді:


14

bsdtar (на основі libarchive) може фільтрувати tar (та деякі інші архіви) від stdin до stdout. Наприклад, він може передавати лише імена файлів, що відповідають шаблону, і може робити s/old/new/перейменування. Це вже упаковано для більшості дистрибутивів, наприклад, як bsdtarв Ubuntu.

sudo apt-get install bsdtar   # or aptitude, if you have it.

# example from the man page:
bsdtar -c -f new.tar --include='*foo*' @old.tgz
#create new.tar containing only entries from old.tgz containing the string ‘foo’
bsdtar -czf - --include='*foo*' @-  # filter stdin to stdout, with gzip compression of output.

Зауважте, що у вас є широкий вибір форматів стиснення для введення / виводу, тому вам не доведеться самостійно прокладати через gunzip / lz4. Ви можете використовувати -для stdin із @tarfileсинтаксисом та / або -для stdout як звичайний.


Мій пошук також знайшов цей інструмент модифікації потокового дьогтю, який, як видається, бажає визначити зміни в архіві, які потрібно використовувати за допомогою JavaScript. (Я думаю, вся справа написана в js).

https://github.com/mafintosh/tar-stream


1
Відмінно, не знав, що такий @original.tarпідхід можливий за допомогою bsdtar. Здається, працює і з розширеними атрибутами та стисненням </var/cache/pacman/pkg/libuv-1.7.0-1-x86_64.pkg.tar.xz bsdtar -czf - --include='usr/share/*' @- | tar tvz(і чомусь порожній вибір виділяє серію нульових байтів, але це не є для мене головною проблемою).
Лекенштейн

1
Згідно з моїми тестами, s/old/new/ не працює на файлах, що надходять із старих архівів за допомогою @ old.tgz, він працює лише на реальних файлах, архівуючи безпосередньо з файлової системи. Це справді прикро, як це було б для мене найбільш корисним випадком використання.
барт

4

Найпростішим способом було б скопіювати весь архів; Я припускаю, що ти цього не хочеш робити, тому що він занадто великий.

Звичайні засоби командного рядка ( tar, pax) не підтримують копіювання членів архіву в інший архів.

Якщо вам не потрібно було зберігати право власності, я б запропонував використовувати файлові системи FUSE . Ви можете використовувати archivemount для монтажу архіву як файлової системи; зробіть це для архіву джерела та запустіть tar на змонтованій файловій системі.

archivemount some.tar.gz mnt
cd mnt
tar -cz subdir | ssh example.com tar -xz
fusermount -u mnt

Крім того, ви можете використовувати AVFS :

mountavfs
cd ~/.avfs$PWD/some.tar.gz\#
tar -cz subdir | ssh example.com tar -xz

Крім того, ви можете запустити tarв оригінальному архіві та витягнути на віддалену машину через SSHFS .

sshfs example.com: mnt
cd mnt
tar -xf /path/to/some.tar.gz subdir
fusermount -u mnt

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

tarfileБібліотека Python пропонує досить простий спосіб маніпулювання членами tar, тому ви можете переміщувати їх з одного файлу tar на інший. Він підтримує стандартні формати POSIX (ustar, pax), а також деякі розширення GNU. Ось неперевірений сценарій Python, який зчитує файл tar (можливо, стиснутий gzip або bzip2) на своєму стандартному вході та записує файл tar, стиснутий bzip2 на стандартному виході. Члени з джерела копіюються, якщо вони починають з аргументу, переданого до сценарію.

#!/usr/bin/env python2
import sys, tarfile
source = tarfile.open(fileobj=sys.stdin)
destination = tarfile.open(fileobj=sys.stdout, mode='w:bz2')
for info in source:
    if info.name.startswith(sys.argv[1]):
        destination.addfile(info)
destination.close()

Щоб викликати як

tar_filter <some.tar.gz subdir/ | ssh example.com tar -xj

1
bsdtar (заснований на бібліотеці) може фільтрувати архіви дьогтю на льоту, дивіться мою відповідь.
Пітер Кордес

Завдання полягало в тому, щоб витягнути дані з зображення вбудованого програмного забезпечення, тому власності / членство в групі дійсно важливі. Підхід пітона, однак, може працювати.
Лекенштейн

0

Альтернативний підхід без привілеїв - використовувати fakerootпрограму, щоб зробити вигляд, що вам дозволяється змінити право власності. Хоча інші атрибути tar втрачаються, він зберігає режим, mtime та uid / gid. Ці команди створюють тимчасовий каталог, витягують підмножину файлів і, нарешті, створюють новий архів:

mkdir tmp
<some.tar.gz \
fakeroot -- sh -c 'cd tmp && tar -xzf- subdir/ && tar -czf- subdir' |
   ssh remote@system tar -xzvf-
rm -rf tmp

0

У GNU tarє --deleteможливість:

$ tar -c a b c | tar --delete a | tar -t
b
c

Таким чином, ви можете отримати підмножину вхідного tar, вказавши, що не слід включати у висновок.

На жаль, мені не вдалося отримати --excludeможливість працювати --delete, тому, здається, спочатку вам потрібно отримати чіткий список ( -t) речей, які слід видалити, а потім передати їх іншому виклику tar.

$ tar --delete --no-recursion `tar -t --exclude subdir <some.tar` <some.tar | ssh ...

Або ви можете зберегти список у зовнішньому файлі, якщо він занадто довгий або складний:

$ tar -t --exclude subdir <some.tar >to_delete.lst
$ tar --delete --no-recursion -T to_delete.lst <some.tar | ssh ...

-1

З того, що я знаю, tarкоманда не може використовувати формат дьогтю і як вхід і вихід. Вам доведеться якимось чином витягнути свої файли локально і знову використовувати tar для створення таргефа на ходу, що-небудь подібне ( -замість файлу використовується стандартний ввід / вихід):

tar cf - subdir/ | ssh remote@system 'cd extractdir && tar xvf -'

Зауважте, що tarможливість витягнути tarfile безпосередньо в інший tarfile - цікава ідея ...


Без кореня це втратить всю інформацію про власність / групу, яку я явно хочу зберегти.
Лекенштейн

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