将 tar 解压缩到目录,删除其中包含的所有不存在于存档中的文件

将 tar 解压缩到目录,删除其中包含的所有不存在于存档中的文件

假设我有一个大焦油,我定期将其内容提取到固定位置。

我希望将此位置保留为提取的 tar 的原始实例,并且我可以避免总是擦除输出目录只是为了使用 tar 可能具有的小更改来更新它的非常浪费的过程--keep-newer-files

但是,如何从输出位置删除存档中不再存在的文件呢?

答案1

标准tar命令有一种列出存档内容的方法。其缩写形式是tar -tf archive.tar.

通过将其与findgrep和 命令替换一起使用,您将得到以下结果:

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 工具或兼容的 和spongefrom 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才能使其正确,而这里的命令并不消除任何东西,它都会打印出什么不是包含在我们的档案中。

相关内容