tar命令:在当前目录中添加包括.svn等所有文件和目录

133

我试图压缩一个目录并使用tar.gz

tar -czf workspace.tar.gz *

生成的tar包在子目录中包括.svn文件夹,但在当前目录中不包括(因为在传递给tar之前,*只会扩展为“可见”文件)。

我试过使用 tar -czf workspace.tar.gz .,但是读取时出现错误,因为'.'已经改变:

tar: ./workspace.tar.gz: file changed as we read it

有没有什么技巧可以使*匹配一个目录中的所有文件(包括以点开头的文件)?

(在 Linux SLES-11 上使用 bash(2.6.27.19))


7
这个问题或许应该发到超级用户网站上? - Peter Jaric
16个回答

115

不要在你打包的目录中创建tar文件:

tar -czf /tmp/workspace.tar.gz .

这个方法是可行的,但是当你解压缩时它会在当前目录中将文件提取到各个地方。更好的做法是:

cd ..
tar -czf workspace.tar.gz workspace

或者,如果你不知道你所在的目录名称:

base=$(basename $PWD)
cd ..
tar -czf $base.tar.gz $base

假设你没有通过符号链接到达当前目录,并且Shell不会尝试通过符号链接向后跳转,bash在这方面不可信。如果你需要担心这个问题,使用cd -P ..进行物理更改目录。我认为这不是默认行为真是太愚蠢了,在某种程度上很混乱,至少对于那些从未考虑过cd ..的人来说。


讨论中的一条评论如下:

我[...]需要排除顶级目录,我[...]需要将tar放置在基础目录中。

评论的第一部分并没有太多意义 - 如果tar文件包含当前目录,当你从该存档中提取文件时,它不会被创建,因为根据定义,当前目录已经存在(除非在非常奇怪的情况下)。

评论的第二部分可以通过以下两种方式之一解决:

  1. 创建文件的其他位置 - /tmp是一个可能的位置 - 然后在完成后将其移回原始位置。
  2. 或者:如果你使用GNU Tar,请使用--exclude=workspace.tar.gz选项。等号后面的字符串是模式 - 示例是最简单的模式 - 完全匹配。如果你正在当前目录工作,与建议相反,可能需要指定--exclude=./workspace.tar.gz;如果你正在向上一级工作,则可能需要指定--exclude=workspace/workspace.tar.gz。如果你有多个tar文件要排除,请使用'*',例如:--exclude=./*.gz

2
回答不错,但我有一个情况,必须在要打包的目录内运行此命令。我没有足够的权限在外部运行它。 - Hexodus
一个完美的打包位置肯定是/tmp。 - Andre Fellows
1
@Hexodus:如果需要的话,您可以从当前目录运行命令,但是您需要确保 tar 不会尝试归档它正在创建的文件。有多种方法可以实现这一点,特别是使用 GNU Tar。最简单的方法是在另一个目录中创建 tar 文件——例如 /tmp。如果您无法在要归档的目录之外创建文件,则使用 --exclude="name-of-tar-file" 选项。如果您使用的是替代(非 GNU)版本的 tar,请阅读其手册。 - Jonathan Leffler
1
使用 cd .. 可以更改当前目录。如果你想回到之前的目录(在 tar 命令之后),使用 cd -,你就会回到之前的同一个目录。 - Thomas

91

需要执行以下几个步骤:

  1. * 替换为 .,以包含隐藏文件。
  2. 要在相同目录下创建存档文件,可以使用 --exclude=workspace.tar.gz 来排除存档文件本身。
  3. 为了避免在存档尚未创建时出现 tar: .: file changed as we read it 错误,请确保它存在(例如使用 touch),以便 --exclude 与存档文件名匹配。(如果该文件不存在,则不匹配)

综合起来,得到以下脚本:

touch workspace.tar.gz
tar -czf workspace.tar.gz --exclude=workspace.tar.gz .

11
我阅读了所有的回答和评论,发现这是在同一目录下创建tar包最好的方式。从这个答案中,我也明白了为什么会出现这个错误。 - Szymon Sadło
如果您想在压缩tar文件时查看进度,可以添加一个额外的标志--verbose,如下所示:-czvf - Mastrianni

48

如果你确实不想在tarball文件中包含顶层目录(通常这是个坏主意):

tar czf workspace.tar.gz -C /path/to/workspace .

我需要排除顶级目录,并将tar文件放在基础目录中。 - Micha
@Micha 制作一个 Bash 脚本来归档并复制文件。 - Fedir RYKHTIK
3
我认为您漏掉了-czf中的横线。 - UpTheCreek
10
tar命令:tar的第一个参数应该是一个操作函数,可以是字母Acdrtux之一或长格式操作名之一。操作字母无需加前缀“-”,并且可以与其他单字母选项组合使用。 - rkhayrov
10
仍然无效,我的 tarball 顶层目录仍为“.”。 - A. Gille

20

如果您想要压缩当前目录,请尝试以下方法:

tar -czf workspace.tar.gz . --exclude=./*.gz

2
但现在它抱怨说文件“.”在读取时已更改。我能确定所有文件都已包含吗? - Jaan
1
这将排除目录中所有的.gz文件。 - omerfarukdogan

14
你可以返回上级目录并执行以下操作以包含隐藏目录:
cd ..
tar czf workspace.tar.gz workspace

假设您想要压缩的目录名为workspace。


这也避免了文件更改的问题。 - Jonathan Leffler
当用户在父文件夹中没有写入权限时,程序无法正常工作。 - Joachim Wagner
确切地说,@JoachimWagner! - Adarsh Sojitra
1
@JoachimWagner。如果您没有写入权限,请将其更改为:tar -czf /path/to/where/you/do/have/permission/workspace.tar.gz workspace - bramp
1
我必须在czf之前去掉-才能使其正常工作。否则,我会收到“无法统计:没有这样的文件或目录”错误消息。 - Phemelo Khetho

7
您可以使用--exclude来修复.表单:
tar -czf workspace.tar.gz --exclude=workspace.tar.gz .

5

另一个解决方案,假设文件夹中的项目数量不是很大,并且假设所有名称都不包含shell解释为分隔符(空格)的字符:

tar -czf workspace.tar.gz `ls -A`

ls -A 命令可以列出所有文件,包括隐藏文件,但不会列出当前目录和上级目录(即"."和".."),与 ls -a 命令不同。)

4

更新:我为原帖作者的评论添加了一个修复。

tar -czf workspace.tar.gz .

确实,使用该命令会改变当前目录,但为什么不将文件放在其他地方呢?

tar -czf somewhereelse/workspace.tar.gz .
mv somewhereelse/workspace.tar.gz . # Update

文件将在之后进行处理,需要在工作区中。虽然有点丑陋,但这只是必需的(整个过程只是一个解决方法...)。 - Micha
好的,我会为此添加修复 :) - Peter Jaric
如果您需要能够重复运行此操作,请在tar命令之前添加“rm workspace.tar.gz”。 - Peter Jaric
如果你想将整个驱动器打包成tar文件,并将其存储到同一驱动器中,似乎没有太多选择。 - BeeOnRope

4

实际上问题出在压缩选项上。诀窍是将tar结果传输到压缩程序而不是使用内置选项。顺便说一句,这也可以带来更好的压缩效果,因为您可以设置额外的压缩选项。

最小化tar:

tar --exclude=*.tar* -cf workspace.tar .

将其传输到您选择的压缩器。这个示例很冗长,使用最大压缩的xz:

tar --exclude=*.tar* -cv . | xz -9v >workspace.tar.xz

该解决方案已在Ubuntu 14.04和Windows 7上的Cygwin上进行测试。 这是一个社区维基答案,如果您发现错误,请随意编辑。


谢谢!救了我的命 - Steven

2

我曾经遇到过类似的情况。我认为最好是在其他地方创建tar文件,然后使用-C选项告诉tar压缩文件的基本目录。例如:

tar -cjf workspace.tar.gz -C <path_to_workspace> $(ls -A <path_to_workspace>)

这样就不需要排除您自己的tar文件。如其他评论中所述,-A将列出隐藏文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接