ChatGPT解决这个技术问题 Extra ChatGPT

tar 目录,但不要在存档中存储完整的绝对路径

我在备份 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 和备份的问题,但大多数都要求删除整个子目录结构(扁平化),或者只是添加或删除名称中的初始 /(我不知道提取时它到底发生了什么变化),但没有更多。

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

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 想要创建一个存档,而不是提取一个。

S
SHernandez
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 如何删除它?
T
Toby Speight

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

创建没有完整路径的压缩包:完整路径 /home/testuser/workspace/project/application.war 我们想要的只是 project/application.war 所以: tar -cvf output_filename.tar -C /home/testuser/workspace project 注意:workspace 和 project 之间有一个空格; tar 将用 project 替换完整路径。通过更改目标路径(默认为 .,即当前目录)提取 tarball tar -xvf output_filename.tar -C /home/deploy/ tar 将根据给定路径提取 tarball 并保留创建路径;在我们的示例中,文件 application.war 将被提取到 /home/deploy/project/application.war。 /home/deploy:在提取项目中给出:在创建 tarball 时给出

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

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

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

似乎 tar v2.8.3 之前的 -C 选项不能在所有平台(操作系统)上始终如一地工作。 -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。您的回答说该工具的工作方式与文档所说的工作方式以及它在我的系统上的工作方式相反,所以这是一个错误的答案。你可以很容易地修复它。
l
laktak

一个小细节:

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,这是一个常见的混淆来源。
W
WLatif

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

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 目录)
R
Rod

使用“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。我的方式更正确使用,这是我的意见。
H
Hirurg103

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

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

d
dexter2305

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

tar 文件名可能无关紧要,因为原始文件夹现在是存档条目

对内容无关紧要的 tar 文件名现在可以用于其他目的,例如序列号、定期备份等。