当模式以“/”结尾时,GNU tar 的“转换”选项表现不一致

当模式以“/”结尾时,GNU tar 的“转换”选项表现不一致

tar当我使用转换路径元素的选项时,我遇到了 GNU 的以下奇怪行为--transform:当我尝试tar整个子目录并想要转换到该目录的路径时,转换是不是当转换模式明确包含时,它不仅应用于目录本身,还应用于其内容/

重现:

  • 创建一个包含虚拟内容的目录test-dir
    $ mkdir test-dir
    $ touch test-dir/test{1..50}.txt
    
  • tar该目录重命名为test-dir/to transformed-dir/,并指示tar打印转换后的名称以进行检查:
    $ tar --transform="s,^test-dir/,transformed-dir/," --show-transformed-names -cvf test.tar test-dir
    test-dir/
    transformed-dir/test25.txt
    transformed-dir/test29.txt
    transformed-dir/test47.txt
    ...
    

如您所见,目录本身是不是尽管重命名适用于目录中的所有文件,但已正确重命名。

  • 为了进行比较,使用相同的转换,但是没有尾随/
    $ tar --transform="s,^test-dir,transformed-dir," --show-transformed-names -cvf test2.tar test-dir
    transformed-dir/
    transformed-dir/test25.txt
    transformed-dir/test29.txt
    transformed-dir/test47.txt
    ...
    

现在,目录本身正确重命名。

当省略锚点时,该行为不会改变,并且与是否在命令行中^指定要压缩的目录无关。/

  • 我想知道问题是否是当/指定时,在目录的情况下全部的文件名可能会被替换。但是,当指定将重命名整个文件的转换时,它可以正常工作:
    $ tar --transform="s,^test-dir/test29.txt,transformed-dir/file.txt," --show-transformed-names -cvf test3.tar test-dir
    test-dir/
    test-dir/test25.txt
    transformed-dir/file.txt
    test-dir/test47.txt
    ...
    

所以看来尾随确实/是问题所在。这是一个功能、一个错误,还是我以某种方式误解了该选项的范围/语法?版本tar是 GNU tar 1.28。

答案1

正如 @muru 和 @UncleBilly 的评论所指出的,这里的问题可能是 GNU 的误解和不幸的输出的混合体tar

  • 当以“详细”模式 ( -v) 运行时,(GNU)将在所有引用目录而不是文件的条目后tar附加尾随。/
  • 然而,这/当然是不是实际目录名称的一部分存储在文件系统数据中。
  • 该转换似乎适用于目录条目的“实际”名称,其中才不是匹配模式,因为不是名称的一部分。some_name//

因此,该选项看似不一致的行为--transform是由于打印目录名称与实际(和内部使用)目录名称。

正如@UncleBilly 所指出的,如果你想确保只有完全匹配指定名称的目录才应该被重命名,像这样的转换语句

--transform='s,^path/to/dir\($\|/\),newname\1,'

将确保仅重命名目录path/to/dir(应用字符串结尾锚点的位置$)及其内容path/to/dir/fileXXX.yyydir紧随其后的位置/)。\1替换文本中的反向引用将确保/在转换目录内文件的路径名时不会省略 。

相关内容