извлечение дегтя в деготь

У меня сейчас есть tar.gz, и я хочу извлечь из него всего один или два файла и упаковать/добавить их в новый tar.gz, и все это за один раз. Конечно, я могу просто сохранить во временный файл и работать с ним, но АБСОЛЮТНОЕ требование состоит в том, чтобы сделать все это без какого-либо промежуточного вывода файла, т.е. конвейера. Другими словами, я хотел бы что-то вроде следующего псевдокода (очевидно, синтаксис неверен):

tar -xvf first.tar.gz subdir1/file1 subdir2/file2 | tar cf - | gzip > second.tar.gz

Кто-нибудь знает правильный синтаксис для этого? Я пробовал много вариантов, но безрезультатно.

Я также очень открыт к идее использования cpio, но опять же, я озадачен тем, как правильно настроить синтаксис, и, насколько я понимаю, cpio принимает только архивы или имена файлов, а не файлы.

Любая помощь будет оценена.

РЕДАКТИРОВАТЬ: внутри архива нет конкретного шаблона имени файла для извлечения. Учитывая, что BSD и GNU tar могут искать только по одному шаблону за раз, я не уверен, что вообще возможно использовать флаги include/exclude соответственно.


person user1522407    schedule 13.07.2012    source источник
comment
Имеют ли имена файлов, которые вы собираетесь извлечь из первого архива, какой-то шаблон?   -  person fvwmer    schedule 13.07.2012
comment
Я отредактировал приведенные ниже решения GNU tar и BSD tar, чтобы показать результаты моего тестирования, которые позволяют указать несколько файлов для удаления или включения. Таким образом, оба решения работают для вашей проблемы.   -  person Mark Adler    schedule 14.07.2012


Ответы (4)


Я предполагаю, что вы используете или можете получить GNU tar.

Вы можете использовать опцию --delete для преобразования одного файла tar в другой. Например.:

% tar cf x.tar a b c d
% tar tf x.tar
a
b
c
d
% cat x.tar | tar f - --delete b c > y.tar
% tar tf y.tar
a
d
%

Обратите внимание, что вы можете указать несколько имен для удаления. Тогда вам просто нужно выяснить, как указать все файлы, от которых нужно избавиться, в командной строке, а не файлы, которые нужно сохранить.

person Mark Adler    schedule 13.07.2012
comment
Это хорошо, я рекомендую добавить немного к нему. вместо › y.tar просто переходите к следующему tar. например cat x.tar | tar f - --delete b c | tar tf - - person Trenton D. Adams; 08.05.2020

Если вы знаете шаблон имени файла, который собираетесь извлечь, попробуйте следующее:

tar zcf second.tar.gz --include='filepattern' @first.tar.gz

Вот пример, показывающий включение нескольких файлов:

% tar cf x.tar a b c d
% tar tf x.tar
a
b
c
d
% cat x.tar | tar cf - --include='a' --include='d' @- > y.tar
% tar tf y.tar
a
d
%
person fvwmer    schedule 13.07.2012
comment
Это тоже работает! Правда только для BSD tar. К сожалению, это не работает для GNU tar. Таким образом, есть решение для обоих, но этот BSD tar предлагает решение, более близкое к тому, о чем просили. - person Mark Adler; 13.07.2012

Ни одно из вышеперечисленных решений не помогло мне, tar жаловался на создание пустого архива

Вместо этого я просто использовал &&:

tar -xf first.tar.gz subdir1/file1 subdir2/file2 && tar -cvf second.tar --remove-files subdir1/file1 subdir2/file2 

Где --remove-files — опция удаления файлов после добавления в архив.

Другой метод, который я обнаружил, работает:

tar -cf second.tar `tar -tf first.tar.gz /desired/directory`

Обратите внимание, что сохраняется весь контекст каталога, поэтому /желаемый/каталог все еще находится в новом tar.

person Leland    schedule 16.07.2020

При распаковке tar обычно записывает на диск распакованные файлы, а не выходной поток. Вы можете использовать -O или --to-stdout для записи файлов в стандартный вывод, но между файлами не будет разрыва или какого-либо способа узнать, когда заканчивается один и начинается другой.

Кроме того, опция create tar может читать файлы только с диска, а не со стандартного ввода. Это имеет смысл из-за вышеупомянутой проблемы с знанием того, когда заканчивается один файл и начинается другой.

Это означает, что нет способа сделать это из командной строки так, как вы хотите.

Тем не менее, я держу пари, что вы могли бы написать сценарий Perl или Python, используя библиотеки, которые вы можете заставить работать строго в памяти.

person DonGar    schedule 13.07.2012
comment
Если работа в памяти является необходимостью, извлечение на электронный диск будет работать в оболочке. - person Barton Chittenden; 13.07.2012
comment
Это возможно с помощью GNU tar (без RAM-диска). Смотрите мой ответ. - person Mark Adler; 13.07.2012
comment
И это возможно с BSD tar, а также (@fvwmer's answer). Будьте осторожнее, когда говорите, что это невозможно сделать. - person Mark Adler; 13.07.2012