Переименовать каталог внутри архива tar

14

Можно ли переименовать каталог внутри архива tar? Мой вариант использования заключается в том, что у меня есть предоставленный извне файл спецификации RPM, в котором предполагается наличие тарбола с определенной структурой каталогов, и у меня есть предоставленный извне тарбол, чье имя каталога верхнего уровня не соответствует ожидаемому файлу спецификации. Я не управляю ни скриптом, который генерирует тарболлы, ни файлом спецификации RPM, поэтому я не могу внести изменения в один из них, чтобы он соответствовал другому.

То, что я делал, - это безнаказанность, изменение имени каталога, а затем создание нового архива, но мне было интересно, есть ли альтернатива этому.

Лорин Хохштайн
источник
3
К сожалению, я сомневаюсь в этом, но мне было бы интересно узнать, есть ли у кого-то еще способ. Я думаю, что вам лучше всего написать сценарий для untar, переименовать и re-tar.
Кевин

Ответы:

8

Это не должно быть очень сложно, по крайней мере для архивов, которые совместимы с форматом старого стиля, где имена файлов хранятся в поле фиксированного размера (100 байт), но я не знаю ни одного инструмента, который может переименовать файл на месте в архиве tar. Кроме того, со сжатым архивом вам все равно нужно будет создать новый файл.

Это должно быть еще проще, но я не знаю ни одного существующего инструмента, который может фильтровать архив, переименовывая файлы по мере необходимости. Вы можете создать один поверх библиотек tar на языках сценариев; например, вот сценарий проверки концепции для переименования каталога в архиве tar с использованием PerlArchive::Tar . Архив загружается полностью в память; это внутреннее ограничение Archive::Tar.

#!/usr/bin/env perl
## Usage: tar-rename OLDPREFIX NEWPREFIX
use strict;
use warnings;
use Archive::Tar;
my ($from, $to) = @ARGV;
my $tar = Archive::Tar->new(\*STDIN);
foreach my $file ($tar->get_files()) {
    my $name = $file->name;
    $name =~ s~\A\Q$from\E($|/)~$to$1~;
    $file->rename($name) unless $name eq $file->name;
}
$tar->write(\*STDOUT);

GNU tar не имеет возможности переименовывать участников на лету, но pax(замена POSIX для cpioand tar) делает. Тем не менее, вы не можете сделать paxчтение и запись из архива. Что вы можете сделать, это представить архив как обычное дерево через AVFS и создать новый архив с помощью pax. При этом сохраняются имена файлов (за исключением преобразованных), содержимое, время и режимы, но при этом восстанавливается право собственности на файл (если только он не выполняется от имени пользователя root).

mountavfs
cd "~/.avfs$PWD/old.tgz#"
pax -w -s '!bar!baz!' -s '!bar/!baz/' . | gzip >new.tgz
Жиль "ТАК - перестань быть злым"
источник
GNU Tar существует --transformпо крайней мере с 2010 года, что позволяет переименовывать файлы на лету. Для примера, см .: scriptsandoneliners.blogspot.com/2019/11/…
A.Danischewski
@ A.Danischewski --transformпозволяет переименовывать файлы при создании или распаковке архива. Но как переименовать файлы в архиве, не распаковывая его? (Извлекая это не является хорошим решением , вы не можете иметь достаточно места на диске, вы не можете иметь права доступа для сохранения информации собственности, вы не можете иметь возможность сохранить временные метки точно ...)
Жиля SO- перестать быть злом "
Ладно, да, я только что видел ваше сообщение о том, что «GNU tar не позволяет переименовывать участников на лету» - это происходит, но только при входе / выходе. Если вы хотите изменить имена в существующем архиве, вы можете использовать archivemount, чтобы смонтировать его в каталог, изменить любые имена, которые вы хотите, и размонтировать его.
А.Данищевский
3

Как взлом sr_, так и ответ Жиля выглядят очень хорошо, но если ваша проблема - это просто имя корневого каталога целевого архива, при запуске rpmbuild, другое решение может заключаться в том, чтобы переопределить %setupмакрос, чтобы выполнить необходимое переименование директории .

Нечто подобное (вы должны адаптировать и уточнить это в вашей фактической конфигурации, в частности , замена old-dirи desired-dirи использовать правильный инструмент декомпрессии) это в ~/.rpmmacros:

%setup cd ../BUILD \
rm -rf cd-player \
bunzip2 -dc ../SOURCES/%{name}-%{version}.tar.bz2 | tar -xvvf - \
if [ $? -ne 0 ]; then \
  exit $? \
fi \
mv <old-dir> <desired-dir> \
cd <desired-dir> \
cd ../BUILD/cd-player \
chmod -R a+rX,g-w,o-w .

Честно говоря, я бы этого не сделал, если бы не самая экзотическая ситуация, но, возможно, у вас все получится :)

Гвидо
источник
2

Просто просмотрите эту страницу, но нашли правильный ответ в другом месте:

http://www.rpm.org/max-rpm/s1-rpm-inside-macros.html

В нем говорится, что вы можете передать -n макросу% setup, чтобы сообщить rpmbuild имя папки верхнего уровня в tarball

Найл
источник
1

Гадкий взлом, но, возможно, это вам поможет, дурачиться tarс символическими ссылками:

$ mkdir a b
$ date >> b/foo
$ tar zcvf b-foo.tgz b/foo
$ rm -rf b
$ ln -s a b

$ tar zxvf b-foo.tgz                                                              
x b/foo: Cannot extract through symlink b
tar: Error exit delayed from previous errors.
$ tar zxvPf b-foo.tgz                                                             
x b/foo
$ ls a
foo

Размышляя об этом, это, вероятно, не так, как rpmне позволит вам возиться с аргументами tar, не так ли? (Правка: может быть, какой-нибудь хитрый tarскрипт-обертка $PATHпоможет вам обойти это.)

Sr-
источник