使用 bash 脚本在子目录中查找 tar 档案

使用 bash 脚本在子目录中查找 tar 档案

我有一个包含许多(> 5000)文件夹的目录:

folder1
folder2
folder3
...

所有这些文件夹都有许多子目录。在每个文件夹的特定子目录中,可能有一个tar.gz存档。如果一个文件夹包含一个tar.gz存档,则它只有一个,并且位于特定的子目录中。

例如:

folder1/foo/baz.tar.gz
folder2/bar/qux.tar.gz
folder3 [no tar.gz file in this folder]
...

我需要编写一个 bash 脚本来完成以下任务:

  • 我想循环遍历每个文件夹,找到tar.gz存档(如果存在),并将其内容解压到不同的目录中(对于所有找到的存档都是相同的)。
  • 找到每个tar.gz存档后,我还需要在与tar.gz存档相同的目录中移动更多文件,可能需要存储存档的路径。

我可以列出所有档案:

find . -name "*tar.gz"

我想知道操作获得的命令是否是最佳解决方案,或者循环遍历每个目录会更好......

最优化的方法是什么?应该如何进行呢?

答案1

find您基本上可以在的选项中执行任何单个操作或操作列表-exec,那么为什么不untar直接在 中执行每个存档呢find -exec?对于复杂的命令,通常使用该-exec功能来调用 shell,并使用 shell 命令的-c选项将要运行的实际命令传递给它。例如(实际上有一种更简单的方法来执行这个实际示例,但它是为了展示想法):

-exec sh -c 'mv "$1" "~/$1"' sh {} ';'

这将为找到的每个文件启动一个 shell,并将该文件移动到您的$HOME目录。请注意,它{}用于将找到的文件名作为 shell 位置参数传递,即。$1,因此在 shell 命令中$1使用的是 ,而不是{}。在您的情况下,这种类型的解决方案类似于:

-exec sh -c 'tar xvf "$1" -C "$(dirname $1)"' sh {} ';' 

这个想法是这个习惯用法带来了您最喜欢的 shell 的所有功能之内命令find。 (是的,您可以使用bashzsh代替sh,只是要注意sh加载速度要快得多,并且当您处理许多文件时,这可能会增加)。

如果这是您重复执行的操作,或者您事先预计操作会花费很长时间,如果你有一个多核 cpu,那么考虑第二个选项可能对你有利 - 将你的文件列表通过 GNU 管道传输parallel,并让它untar在所有核心上同时执行操作。初学者可以试试这个:

find . -name "*tar.gz" -type f -print0 |
  parallel -0 tar xvf {} -C {//}

作为额外的效率,上述答案不再需要使用外部dirname命令,因为 GNU 并行本身可以更有效地完成它。这就是他们{//}正在做的事情。

警告:我不是这方面的专家,parallel并且在没有实际使用经验的情况下提供该选项,因此如果其他人可以插话这是否是正确的方法,那就太好了。

答案2

您可以使用 find 命令将 tarball 路径传递给可以解压它们的脚本(我尚未对此进行测试):

$ cat script
#!/bin/bash --
tarball="${1}"
dir="$(dirname ${tarball})"
tar xvf "${tarball}" -C "${dir}"

然后使用 find 调用脚本:

$ find . -type f -name '*.tar.gz' -exec ./script "{}" \;

或者在一个 find 命令中(快速测试):

find . -type f -name '*.tar.gz' -exec sh -c 'dir="$(dirname ''"{}"'')"; tar xvf "{}" -C "${dir}"' \;

相关内容