重命名 tar 存档内的目录

重命名 tar 存档内的目录

是否可以重命名 tar 存档中的目录?我的用例是,我有一个外部提供的 RPM 规范文件,该文件假定具有特定目录结构的 tarball,并且我有一个外部提供的 tarball,其顶级目录名称与规范文件所期望的不匹配。我无法控制生成 tarball 的脚本或 RPM 规范文件,因此我无法对其中任何一个进行更改以匹配另一个。

我一直在做的是解压,更改目录名称,然后创建一个新的 tarball,但我想知道是否有其他方法可以做到这一点。

答案1

这应该不是很困难,至少对于与旧式格式兼容的档案来说,其中文件名存储在固定大小(100 字节)字段中,但我不知道有任何工具可以重命名文件位于 tar 存档中。此外,对于压缩存档,您无论如何都需要创建一个新文件。

它应该更容易,但我不知道有任何现有工具可以过滤存档,并在文件运行时重命名文件。您可以在脚本语言的 tar 库之上构建一个;例如,这是一个概念验证脚本,用于使用以下命令重命名 tar 存档中的目录Perl 与Archive::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 的cpio和替代品tar)确实如此。但是,您无法pax同时从存档中进行读取和写入。您可以做的是将存档作为常规树公开AVFS,并创建一个新的存档pax。这会保留文件名(转换后的除外)、内容、时间和模式,但会将文件所有权重置给您(除非以 root 身份执行)。

mountavfs
cd "~/.avfs$PWD/old.tgz#"
pax -w -s '!bar!baz!' -s '!bar/!baz/' . | gzip >new.tgz

答案2

sr_ 的 hack 和 Gilles 的答案看起来都很好,但如果您的问题只是目标 tarball 的根目录名称,则在运行 rpmbuild 时,不同的解决方案可能是重新定义宏%setup来执行所需的目录重命名。

类似的东西(您必须根据您的实际配置进行调整和完善,特别是替换old-dirdesired-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 .

老实说,如果不是在最奇特的情况下,我不会这样做,但你的情况可能就是这样:)

答案3

只需查看此页面即可在其他地方找到正确的答案:

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

它表示您可以将 -n 传递给 %setup 宏来告诉 rpmbuild tarball 中顶级文件夹的名称

答案4

这篇文章非常接近我所需要的,但没有雪茄。 Archive::Tar 内部的重命名功能弄乱了我的文件夹。它对于文件来说效果很好,但是文件夹出来时没有尾部斜杠(/)。例子:

$VAR1 = [
          'old_root_folder/',
          'old_root_folder/.dockerignore',
          'old_root_folder/.github/',
.....

$VAR1 = [
          'newrootfolder',
          'newrootfolder/.dockerignore',
          'newrootfolder/.github/',
......

请注意,根文件夹不再有斜杠指定!事实证明这并不重要。新的存档可以正常提取,文件夹不以斜杠结尾

我最终得到了以下 Perl 片段:

sub renameRootFolderInTar
{
    my $file = shift;
    my $new_root_folder_name = shift;
    my $tar = Archive::Tar->new($file);
    my @files_in_archive = $tar->list_files;
    my $root_folder = @files_in_archive[0]; # whatever they named the root folder in the archive
    $root_folder =~ s/\/$//g;
    foreach(@files_in_archive)
    {
        my $this_archive_file = $_;
        my $dest = $this_archive_file;
        $dest =~ s/^$root_folder\/(.*)/$new_root_folder_name\/$1/g;
        $tar->rename($this_archive_file,$dest);
    }
    my $success = $tar->write( "renamed.tar.gz", COMPRESS_GZIP );
    if($success)
    {
        unlink $file;
        return "renamed.tar.gz";
    }
    else
    {
        print "Sorry, there was a problem when dealing with the raw archive $file:\n";
        print "Could not save renamed.tar.gz\n";
        exit;
    }
}

诚然,这假设存档中的第一个条目是一个文件夹。但你明白了。

相关内容