【问题标题】:Tar a directory, but don't store full absolute paths in the archivetar 目录,但不要在存档中存储完整的绝对路径
【发布时间】:2013-09-11 23:02:22
【问题描述】:

我在备份 shell 脚本部分有以下命令:

tar -cjf site1.bz2 /var/www/site1/

当我列出档案的内容时,我得到:

tar -tf site1.bz2
var/www/site1/style.css
var/www/site1/index.html
var/www/site1/page2.html
var/www/site1/page3.html
var/www/site1/images/img1.png
var/www/site1/images/img2.png
var/www/site1/subdir/index.html

但我想从存档中的目录和文件名中删除 /var/www/site1 部分,以简化提取并避免无用的常量目录结构。永远不知道,以防万一我在/var/www下没有存储网络数据的地方提取备份网站。

对于上面的例子,我想要:

tar -tf site1.bz2
style.css
index.html
page2.html
page3.html
images/img1.png
images/img2.png
subdir/index.html

所以,当我提取时,文件被提取到当前目录中,之后我不需要移动提取的文件,因此保留了子目录结构。

stackoverflow 和网络上的其他地方已经有很多关于 tar 和备份的问题,但大多数都要求删除整个子目录结构(展平),或者只是添加或删除初始 / in名称(我不知道提取时它到底发生了什么变化),但没有更多。

在阅读了一些在这里和那里找到的解决方案以及手册之后,我尝试了:

tar -cjf site1.bz2 -C . /var/www/site1/
tar -cjf site1.bz2 -C / /var/www/site1/
tar -cjf site1.bz2 -C /var/www/site1/ /var/www/site1/
tar -cjf site1.bz2 --strip-components=3 /var/www/site1/

但它们都没有按我想要的方式工作。有些什么都不做,有些则不再归档子目录。

它在一个由 Cron 启动的备份 shell 脚本中,所以我不太清楚,是哪个用户运行它,路径是什么,当前目录是什么,所以所有东西都需要写绝对路径,最好不要更改当前目录以避免在脚本中进一步破坏某些内容(因为它不仅备份网站,还备份数据库,然后将所有内容发送到 FTP 等)

如何做到这一点?

我是否误解了选项 -C 的工作原理?

【问题讨论】:

  • 嗯,-C 只是表示“更改目录”,而替换路径(或前缀)只能由 --transform 完成。里夫superuser.com/questions/595510/prepend-prefix-in-tar/595512 你可以简单的 -C (更改目录)和 --transform 它:``` tar cjf site1.bz2 --transform "s/^\.\//$targetbase/" -C /var/www/site1 . ```
  • 这是一个很好的问题,遗憾的是,到目前为止没有一个答案是令人满意的。我们还没有从一些聪明人那里听到我们如何可能只将单个文件 style.css(上面的示例)提取到当前目录而不参考原始位置或目录树?我不想用不需要的新树结构弄乱我的当前目录。听起来像是多年来一直被忽视的 tarball 的严重缺陷。
  • @elmclose 你误解了这个问题。 OP 想要创建一个存档,而不是提取一个。

标签: linux bash backup tar


【解决方案1】:
tar -cjf site1.tar.bz2 -C /var/www/site1 .

在上面的例子中,tar 在执行它的操作之前将更改为目录/var/www/site1,因为给出了选项-C /var/www/site1

来自man tar

OTHER OPTIONS

  -C, --directory DIR
       change to directory DIR

【讨论】:

  • 不要错过最后的点,这很重要 ;-)
  • 如果您还想根据通配符选择要备份的文件呢? -C /var/www/site1 *.dat 不起作用:(
  • 圆点告诉tar 归档当前目录中的所有内容。而-C 设置当前目录。
  • 这很好用。我发现保留目录名称(只是不是完整路径)很有用,所以我做了以下操作:tar -czvf site1.tar.gz -C /var/www/ site1(注意空格,我仍在使用 -C 来 cd 到父目录,并指定dir 到 tar 而不是点)
  • 我在 tar 路径中得到一个前导点,例如./folders这个怎么去掉?
【解决方案2】:

-C 选项有效;只是为了澄清,我将发布 2 个示例:

  1. 创建一个没有完整路径的压缩包: 完整路径 /home/testuser/workspace/project/application.war 而我们想要的只是 project/application.war 所以:

    tar -cvf output_filename.tar  -C /home/testuser/workspace project
    

    注意:workspaceproject之间有一个空格; tar 将用 project 替换完整路径。

  2. 通过更改目标路径提取tarball(默认为.,即当前目录)

    tar -xvf output_filename.tar -C /home/deploy/
    

    tar 将根据给定路径提取 tarball 并保留创建路径;在我们的示例中,文件application.war 将被提取到/home/deploy/project/application.war

    /home/deploy:在提取时给出
    project:在创建压缩包时给出

注意:如果要将创建的 tarball 放在目标目录中,只需在 tarball 名称前添加目标路径即可。例如:

tar -cvf /path/to/place/output_filename.tar  -C /home/testuser/workspace project

【讨论】:

  • 上例中如何为文件选择添加通配符?
  • 通配符的问题是shell将它们扩展为匹配的文件名,如果引用它们,tar不会扩展它们......
  • 我在 Ubuntu 18.04 上试过这个,但没有运气。我不确定我错过了什么。我的标准输出在打包时可以正确显示,但是当我解压它时,它仍然具有完整路径
【解决方案3】:

似乎-C tar v2.8.3 之前的选项无法在所有平台(操作系统)上始终如一地工作。据说-C 选项会将目录添加到存档中,但在 Mac 和 Ubuntu 上,它会在生成的 tar.gz 文件中添加绝对路径前缀。

tar target_path/file.tar.gz -C source_path/source_dir

因此一致且健壮的解决方案是将cd 放入source_path(source_dir 的父目录)并运行

tar target_path/file.tar.gz source_dir

tar -cf target_path/file.tar.gz source_dir

在您的脚本中。这将删除生成的 tar.gz 文件目录结构中的绝对路径前缀。

【讨论】:

  • 使用 -C 选项 DID 删除 Fedora 29 上生成的 tar.gz 文件中的绝对路径前缀。您的答案是否特定于某些系统?
  • @EL_DON:我没有在 Fedora 上测试 -C 选项,但理想情况下,tar 应用程序软件应该在每个平台上始终如一地工作,除非它是 tar 应用程序中的错误。 -C 选项,我在 Mac 10.8 和 Mac 10.13 以及 Ubuntu(我不记得的版本)上进行了测试。但是从 tar v2.8.3 开始,该命令已更改为 tar -cf target_path/file.tar.gz source_dir 并且如果您添加 -C 选项,它仍然不会删除生成的 tar.gz 文件中的绝对路径前缀。
  • 我在centOS系统上再次测试。在示例中创建所有路径并运行命令后(在tar 之后添加-cvf),我发现生成的 tar.gz 文件内部没有绝对路径,这与其他几个答案一致。如果您认为 tar 在我用于测试的两个系统上都已损坏或已过时,请链接到一些支持您答案的文档。我认为 -C 选项在执行之前会更改目录(与其他答案一样)。当我省略它时,tar 会尝试从./ 添加垃圾,包括从./ 开始的路径。
  • 我使用了这个文档:linux.die.net/man/1/tar 是的,文档说 -C 会改变路径,但在我的 Mac 10.13 上它不起作用。这可能是 tar 应用程序的不一致行为。这意味着这是一个错误。如果您正在编写一个在所有 unix 平台上运行的 shell 脚本,那么最好在运行适用于所有操作系统的代码时保持安全。
  • 您的回答并没有说可能存在错误,更强大的跨平台兼容性解决方案是先cd。您的回答说该工具的工作方式与文档所说的工作方式以及它在我的系统上的工作方式相反,所以这是一个错误的答案。您可以轻松修复它。
【解决方案4】:

以下命令将创建一个根目录“。”并将指定目录下的所有文件放入其中。

tar -cjf site1.tar.bz2 -C /var/www/site1 .

如果你想把所有文件放在 tar 文件的根目录下,@chinthaka 是对的。只需 cd 进入目录并执行以下操作:

tar -cjf target_path/file.tar.gz *

这会将cwd中的所有文件作为根文件放到tar文件中。

【讨论】:

  • 使用 * 不会保存任何“隐藏”的 .files 或 .folders。 (仅供参考,使用 -C 和 * 失败,shell 扩展当前目录,而不是 -C 目录)
【解决方案5】:

使用“point”会创建一个名为“point”的文件夹(在 Ubuntu 16 上)。

tar -tf site1.bz2 -C /var/www/site1/ .

我更详细地处理了这个问题并准备了一个例子。多行录音,还有一个例外。

tar -tf site1.bz2\
    -C /var/www/site1/ style.css\
    -C /var/www/site1/ index.html\
    -C /var/www/site1/ page2.html\
    -C /var/www/site1/ page3.html\
    --exclude=images/*.zip\
    -C /var/www/site1/ images/
    -C /var/www/site1/ subdir/
/

【讨论】:

  • 为什么叫它“点”?它只是.,即当前目录。在tar.gz 结构的上下文中,这只是基础/根/顶层,对吧?
  • 查看快照了解详情image。我的方法用起来更正确,这是我的看法。
【解决方案6】:

如果您想归档子目录并修剪子目录路径,此命令将很有用:

tar -cjf site1.bz2 -C /var/www/ site1

【讨论】:

    【解决方案7】:

    发现tar -cvf site1-$seqNumber.tar -C /var/www/ site1tar -cvf site1-$seqNumber.tar -C /var/www/site1 . 更友好(注意第二个解决方案中的.),原因如下

    • Tar 文件名可以不重要,因为原始文件夹现在是存档条目
    • 对内容无关紧要的 tar 文件名现在可以用于其他目的,例如序列号、定期备份等。

    【讨论】:

      【解决方案8】:

      一个小细节:

      tar -cjf site1.tar.bz2 -C /var/www/site1 .
      

      将文件添加为

      tar -tf site1.tar.bz2
      ./style.css
      ./index.html
      ./page2.html
      ./page3.html
      ./images/img1.png
      ./images/img2.png
      ./subdir/index.html
      

      如果你真的想要

      tar -tf site1.tar.bz2
      style.css
      index.html
      page2.html
      page3.html
      images/img1.png
      images/img2.png
      subdir/index.html
      

      您应该先 cd 进入目录或运行

      tar -cjf site1.tar.bz2 -C /var/www/site1 $(ls /var/www/site1)
      

      【讨论】:

      • 如果您使用ls -A,您也会获得隐藏文件,而无需尝试遍历... 文件,如果在尝试执行 tar 或 rsync 时,这是一个常见的混淆来源解析符号链接。
      猜你喜欢
      • 2014-11-12
      • 1970-01-01
      • 2012-10-05
      • 1970-01-01
      • 2015-11-17
      • 1970-01-01
      • 2011-08-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多