假设我有一个大焦油,我定期将其内容提取到固定位置。
我希望将此位置保留为提取的 tar 的原始实例,并且我可以避免总是擦除输出目录只是为了使用 tar 可能具有的小更改来更新它的非常浪费的过程--keep-newer-files
。
但是,如何从输出位置删除存档中不再存在的文件呢?
答案1
标准tar
命令有一种列出存档内容的方法。其缩写形式是tar -tf archive.tar
.
通过将其与find
、grep
和 命令替换一起使用,您将得到以下结果:
rm -f $(find . -d | head -n -1 | grep -Fv "$(tar -tf archive.tar)")
运行这个在您想要存档内容的目录,并替换archive.tar
为存档文件的路径。
对于最外层命令替换内的管道,从右到左工作:
find . -d
:列出当前目录下的所有文件和目录,按深度优先顺序列出。深度优先排序在这里很重要,因为我们计划使用此文件列表进行删除,因此必须在删除目录本身之前删除目录内容。head -n -1
:从命令中排除最后一行find
。这将删除该条目/path
本身,该条目可能存在于存档中,也可能不存在。如果我们不按照深度优先的顺序做事,那么这将是tail -n -1
。grep -Fv "$(tar -tf archive.tar)"
:将存档列表传递给 grep 命令,然后该命令将从返回的列表中过滤掉这些行find
,因此只有不在存档中的文件才会传递给外部rm
命令。
一些注意事项:
- 这可能不是相当符合 POSIX 标准。不过它应该可以在 GNU bash 中工作。
- 这取决于 tar 如何报告存档内容以及存档的创建方式。特别是,列表必须与
find
报道方式相匹配。对于 GNU tar 和大多数档案,它应该工作。如果它不适合您的情况,您可能可以通过在最里面的命令替换内的 tar 命令的输出上使用sed
或来使其工作。awk
- 在生产数据上使用它之前,请确保并进行测试,如果由于上述两个原因之一而不起作用,则可能会删除一切形成运行它的目录。
答案2
您可以相信,提取的文件的时间晚ctime
于您开始提取存档的时间。
所以:
touch start
tar xf archive.tgz
find . -depth ! -cnewer start -print0 |
sponge /dev/stdout |
xargs -r0 echo rm -d
(这里假设 GNU 工具或兼容的 和sponge
from moreutils
,用于延迟删除,直到收集到完整列表,否则删除文件将更新其父目录的 ctime)。
删除它echo
以实际执行此操作(在您验证它执行了您想要的操作之后)。
答案3
这个grep -v
技巧对我来说不起作用,因为存档有点大,并且命令通过参数列表太长。因此,这是我用来删除 MediaWiki 安装中累积的垃圾的方法:
$ tar -tzf mediawiki-1.35.0.tar.gz | cut -d/ -f2- > foo
$ find /var/www/mediawiki/ | cut -d/ -f5- | while read f;
do grep -qw "^${f}$" foo || echo "not in archive: ${f}"; done
人们必须稍微调整-f
一下参数cut
才能使其正确,而这里的命令并不消除任何东西,它都会打印出什么不是包含在我们的档案中。