我在 Debian 8 系统上编写了一个备份脚本,它使用 tar 命令和“--exclude-from”来排除一些文件/目录。
这很好用,但今天我想排除一些共享相同路径模式的文件,例如/home/www-data/sites/<some_string>log.txt
或/home/www-data/sites/<one_or_two_directories>/vendor
.
我尝试追加/home/www-data/sites/*log.txt
到文件中,但 tar 失败并在 stderr 上输出以下错误:
tar: /home/www-data/sites/*log.txt: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors
我在尝试使用*
or时错过了什么**
吗?
然后我读到了在 Unix 中,程序本身通常不解释通配符这意味着tar*
也不会扩展它**
。
据我所知,我最后的手段是在调用之前使用 bash 扩展列表并将其附加到排除文件中(如果它尚不存在)tar
。有更干净的方法吗?
编辑
这是脚本片段..
# ...
broot=$(dirname "${PWD}")
i="${PWD}/list.include"
x="${PWD}/list.exclude"
o="$broot/archive.tgz"
tar -zpcf $o -T $i -X $x
# ...
这是排除文件..
/etc/php5/fpm
/etc/nginx
/etc/mysql
/home/me/websites/*log.txt
/home/me/websites/**/vendor
目标是排除位于“网站”目录内的所有日志文件以及可在“网站”的任何子目录中找到的所有“供应商”目录。
答案1
shell 扩展参数中的通配符,因此大多数应用程序不需要执行任何通配符扩展。然而 tar 的排除列表做支持通配符,恰好与传统 shell 支持的通配符匹配。请注意可能存在细微差异;例如 tar 无法区分*
,**
而 ksh、bash 和 zsh 可以。对于 tar,*
可以匹配包括 在内的任何字符/
,因此例如排除在层次结构的任何级别*/.svn
调用的文件。您可以在与目录分隔符不匹配的情况下.svn
使用。tar --no-wildcards-match-slash
*
例如,/home/me/websites/*log.txt
排除/home/me/websites/log.txt
、/home/me/websites/foo-log.txt
和/home/me/websites/subdir/log.txt
。排除/home/me/websites/**/vendor
排除/home/me/websites/one/vendor
和/home/me/websites/one/two/vendor
但不排除/home/me/websites/vendor
。使用该--no-wildcards-match-slash
选项,/home/me/websites/*log.txt
不排除/home/me/websites/subdir/log.txt
和/home/me/websites/**/vendor
不排除/home/me/websites/one/two/vendor
。
tar … --exclude='/home/www-data/sites/*include' …
/home/www-data/sites
排除名称以 . 结尾的文件和目录include
。你可能会在没有引号的情况下逃脱,但如果你这样写(因为这样 shell 会在--exclude /home/www-data/sites/*include
tar
看到通配符之前展开通配符)或者如果你使用的 shell 在不匹配的通配符上发出错误信号(例如默认的 zsh ),则不会。 并推荐- 配置)。
该选项--exclude-from
需要文件名。该文件每行必须包含一个模式。不要混淆--exclude
(后跟模式)和--exclude-from
(后跟包含模式的文件名)。
答案2
您的命令可能被不正确地引用(这里快速检查是否按预期工作)。根据参考手册,GNU tar 识别 shell 通配符:
-
--exclude-from=
文件
-X
文件
导致 tar 忽略与中列出的模式匹配的文件文件。