如何在所有子目录中压缩特定文件类型?

115
我想在一个目录及其子目录中打包所有的 .php 和 .html 文件。如果我使用 tar -cf my_archive * 它会将所有文件都打包,这不是我想要的。如果我使用 tar -cf my_archive *.php *.html 它会忽略子目录。如何让它递归地打包但只包括两种类型的文件?
8个回答

196

find ./someDir -name "*.php" -o -name "*.html" | tar -cf my_archive -T -

可以将某个目录下所有后缀为.php或.html的文件打包成一个名为my_archive的压缩包。

@DeeDee 有关文件数量等方面是否有任何限制? - user1566515
1
@DeeDee - 不,我的意思是你不需要括号! - Mike Makuch
1
@user1566515 可能存在一些文件系统限制或总空间限制,这将对您的tar文件设置一个上限。这完全取决于您自己的系统。否则,管道实质上会即时创建tar文件,因此您不会受到文件数量或大小的限制。 - DeeDee
谢谢!如何添加超过2个条件/文件类型? - gluuke
6
对于每个新条件,请使用-o -name [pattern],@gluuke。 - DeeDee
@DeeDee:很抱歉,由于某些原因我得到了“find: paths must precede expression Usage: find [-H] [-L] [-P] [path...] [expression]”的结果。 - gluuke

28

如果您正在使用版本大于4.0的bash,则可以利用shopt -s globstar轻松解决此问题:

shopt -s globstar; tar -czvf deploy.tar.gz **/Alice*.yml **/Bob*.json

这将会添加所有以Alice开头的.yml文件,并从任何子目录中添加所有以Bob开头的.json文件。


3
只使用焦油的答案,在我看来是最好的答案。 - simon
2
尽管使用“**”通配符可以匹配目录,但该命令并不会递归执行(包括子文件夹)。 - Eddie
4
@eddie 是的,它由 shell 进行评估,尽管 bash > 4.0 有一个 shopt -s globstar 选项,因此答案是正确的,实际上是最好的答案。 - Roman Usherenko
1
“-bash: /usr/bin/tar: Argument list too long”这个错误是因为在传递给tar之前,文件列表已经被扩展了,对于大量的文件会导致失败。 - Neek
@dmitry_podyachev 的解决方案很好,使用 find 生成文件列表,然后使用 tar -czf file.tar -T files.txt 将在 files.txt 中命名的文件打包成 tar 文件。 - Neek
显示剩余3条评论

22

其中一种方法是:

tar -cf my_archive.tar $( find -name "*.php" -or -name "*.html" )

然而,这种方法存在一些注意事项:

  1. 如果有任何带空格的文件或目录,则会失败。
  2. 如果文件太多以至于命令行长度已满,则会失败。

解决这些问题的方法是将find命令的内容输出到文件中,然后使用“-T,--files-from FILE”选项进行tar打包。


  1. "失败"的意思是指带有空格的文件将被跳过还是tar归档文件将不会被创建?
  2. 我大约有10万个文件。这是否超过了命令行长度的最大限制?
- user1566515
1
  1. 它将创建档案,但会报告缺少文件。
  2. 那会太长了,我觉得。鉴于此,您最好使用像@DeeDee下面建议的方法,它可以很好地解决这些问题。
- Robin Sheat

4
这将处理具有空格的路径:
find ./ -type f -name "*.php" -o -name "*.html" -exec tar uvf myarchives.tar {} +

2

使用zsh更容易:

tar cvzf foo.tar.gz **/*.(php|html)

1
你是不是想说 -czvf - Jeremy Caney
1
“-” 在 tar 中是可选的。 - John Delaney

2
如果你想生成一个压缩的 tar 文件(.tgz),并且想避免文件名中的空格问题:
find . \( -name \*.php -o -name \*.html \) -print0 | xargs -0 tar -cvzf my_archive.tgz
-print0find 命令的“主要”选项,使用 NULL (\0) 字节来分隔输出文件名,因此可以很好地与 xargs-0 选项配合使用,在这种情况下,它将其(在这种情况下是以 NULL 分隔的)输入附加为命令的参数。
需要在两个 -name 主要选项周围加上括号,否则 -print0 只会输出第二个 -name 的文件名(如果存在 -print-print0 ,则不会有暗示的打印,只有在它们被评估时才会产生影响)。
如果您需要跳过某些文件或目录(例如,如果您使用 Node.js,则跳过 node_modules 目录),请在前面添加一个或多个 -prune 主要选项,如下所示:
find . -name skipThisName -prune -o \
  -name skipThisOtherName -prune -o \
  \( -name \*.php -o -name \*.html \) -print0 | xargs -0 tar -cvzf my_archive.tgz

1
将它们放入一个文件中。
find . \( -name "*.php" -o -name "*.html" \) -print > files.txt

然后将文件用作tar的输入,根据您使用的tar版本使用-I或-T

使用h来复制符号链接

tar cfh my.tar -I files.txt 

你的意思是使用-T files.txt,而不是-I files.txt,但除此之外,这对于文件数量很大且***的扩展超过了shell限制的情况非常有用。 - Neek
你是指-T files.txt,而不是-I files.txt,但除此之外,这对于文件数量较大,***的扩展超过了shell限制的情况非常适用。 - undefined

0

find ./ -type f -name "*.php" -o -name "*.html" -printf '%P\n' |xargs tar -I 'pigz -9' -cf target.tgz

对于多核或单核:

find ./ -type f -name "*.php" -o -name "*.html" -printf '%P\n' |xargs tar -czf target.tgz


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