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


277

在备份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从档案中的目录和文件名中删除该部分,以简化提取过程并避免无用的常量目录结构。永远不会知道,以防万一我将备份的网站提取到Web数据未存储在的地方/var/www

对于上面的示例,我想拥有:

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

因此,当我提取文件时,文件将被提取到当前目录中,而后我无需再移动提取的文件,从而可以保留子目录结构。

关于tar和在网络上stackoverflow以及其他位置进行备份的问题已经很多,但是大多数问题都要求删除整个子目录结构(拼合),或者只是在名称中添加或删除开头的/(我不不知道提取时它到底发生了什么变化),但仅此而已。

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

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。```
Daniele Cruciani

这是一个很好的问题,遗憾的是,到目前为止,没有一个答案令人满意。我们还没有听到一个聪明人的消息,我们怎么可能仅将单个文件style.css(上面的示例)提取到当前目录中而不参考原始位置或目录树?我不想用不需要的新树结构来整理当前目录。听起来像是压缩包的严重缺陷,多年来一直被忽略。
elmclose

Answers:


382
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

152
不要错过最后的

9
如果您还想基于通配符选择要备份的文件怎么办?-C / var / www / site1 * .dat无效:(
Andy Lorenz 2014年

16
点表示tar将所有内容存档在当前目录中。并-C设置当前目录。
拉尔斯·布林霍夫

21
这很好。我发现保留目录名(只是不完整路径)很有用,所以我做了以下工作:(tar -czvf site1.tar.gz -C /var/www/ site1请注意空格,我仍在使用-C cd到父目录,并将目录指定为tar而不是点)
jorfus 2015年

9
我在焦油路径中得到一个前导点,例如,./folders如何将其去除?
Mika571 '17

39

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

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

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

    注意:workspace和之间有一个空格project。tar将用just代替完整路径project

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

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

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

    /home/deploy:提取时
    project给出:创建tarball时给出

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

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

1
在上一个示例中,如何为文件选择添加通配符?
Siva 2015年

通配符的问题在于,shell将其扩展为匹配的文件名,并且如果用引号引起来,则tar不会将其扩展...
Gert van den Berg

我在Ubuntu 18.04上尝试了这个,没有运气。我不确定我缺少什么。打包时,我的标准输出显示正确,但是解压缩后,它仍然具有完整路径
sdc

14

似乎-Ctar v2.8.3之前的选项在所有平台(OSes)上均无法正常工作。-C据说可以在目录中添加选项,但是在Mac和Ubuntu上,它会在生成的tar.gz文件中添加绝对路径前缀。

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

因此,一致且健壮的解决方案是进入cdsource_path(source_dir的父目录)并运行

tar target_path/file.tar.gz source_dir

要么

tar -cf target_path/file.tar.gz source_dir

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


1
使用-C选项DID可以删除fedora 29上生成的tar.gz文件中的绝对路径前缀。您的答案是否特定于某些系统?
EL_DON

@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文件中的绝对路径前缀。
Chinthaka Senanayaka

我再次在centOS系统上进行了测试。在示例中创建所有路径并运行命令(在-cvf之后添加)之后tar,我发现生成的tar.gz文件内部没有绝对路径,这与其他几个答案是一致的。如果您认为在我用于测试的两个系统上tar均已损坏或过时,请链接到一些支持您答案的文档。我认为该-C选项在执行之前会更改目录(与其他答案一样)。当我忽略它时,tar尝试从中添加垃圾./,包括从中开始的路径./
EL_DON

我使用了这个文档:linux.die.net/man/1/tar 是的,文档说-C可以更改路径,但是在我的Mac 10.13上它不起作用。这可能是tar应用程序的不一致行为。这意味着这是一个错误。如果您正在编写要在所有UNIX平台上运行的Shell脚本,那么最好使用在所有OS上都能运行的代码来确保安全。
Chinthaka Senanayaka

您的回答并不表示可能存在错误,而跨平台兼容性更强大的解决方案是cd首先。您的回答是说该工具的工作方式与文档所说的工作方式以及它在我的系统上的工作方式相反,因此答案是错误的。您可以轻松修复它。
EL_DON '19

7

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

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

如果要将所有文件放在tar文件的根目录中,则@chinthaka是正确的。只需进入目录并执行:

tar -cjf target_path/file.tar.gz *

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


1
使用*不会保存任何“隐藏”的.file或.folders。(仅供参考,将-C与*一起使用失败,shell会扩展当前目录,而不是-C目录)
Xen2050

1

使用“ 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的结构中,这仅仅是基础/根/顶层,对吗?
EL_DON

详情请参阅快照图像。我的方式更正确使用,这是我的看法。
谢尔盖·阿萨切夫

0

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

tar -cjf site1.bz2 -C /var/www/ site1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.