Xargs:执行之前将工作目录更改为文件路径?

Xargs:执行之前将工作目录更改为文件路径?

我有一个很大的 RAR 档案文件夹。文件夹层级结构非常复杂。我想一次性解压整个档案集合。

我有以下一行代码,可以起作用:

find -name "*.rar" -print0 | xargs -0 -n 1 -P 4 unrar x

(请注意,我们并行运行四个线程以加快操作速度。:-))

此命令的问题在于 xargs 在每个 RAR 文件的顶层目录中执行。这意味着所有输出都被转储到顶层文件夹中。

相反,我希望输出与 RAR 存档存在于同一文件夹中。

例子:

Top level
 |--FolderA
 |----File1.rar
 |----File2.rar
 |--FolderB
 |----File1.rar
 |----File2.rar
 |----File3.rar
 |--FolderC
 |----File1.rar
 |----File2.rar

每个“File1.rar”文件都包含一个同名文件。因此将它们全部提取到顶层文件夹会导致覆盖问题。

总而言之,我想提取上述层次结构中的所有 RAR 文件。我希望每个 RAR 文件的内容都存在于 RAR 文件所在的文件夹中。

我觉得解决办法是设置工作目录,然后从那里运行 unrar 命令。但是,由于 find 命令给出的是文件名,而不是目录,所以我无法执行类似

| xargs -I{} -n 1 -P 4 cd {} \; unrar x {}

除了编写一个 Perl 或 Python 脚本来包围 unrar 命令并处理将提供的路径拆分成各个部分并执行命令之外,有没有更好的方法来实现这一点?

答案1

存在从路径中提取目录名称 ( dirname) 和文件名 ( ) 的命令。因此,您可以执行类似以下操作basename

find . -name '*.rar' -print0 | \
xargs -0 -I{} -n1 -P4 /bin/sh -c 'cd "$(dirname {})"; unrar x "$(basename {})"'

据我所知,xargs不支持更改目录,因此您需要一些中介来执行此操作,因此/bin/sh。您提到编写一个包装器unrar,这基本上就是它所做的事情,只是采用单行形式。

答案2

使用 GNU Parallel 它看起来像这样:

find . -name '*.rar' | parallel cd {//} '&&' unrar x {/}

GNU Parallel 是一个通用的并行化器,可以轻松地在同一台机器或通过 ssh 访问的多台机器上并行运行作业。

如果你想在 4 个 CPU 上运行 32 个不同的作业,那么并行化的直接方法是在每个 CPU 上运行 8 个作业:

简单调度

当一个进程完成时,GNU Parallel 会生成一个新进程 - 保持 CPU 活跃,从而节省时间:

GNU 并行调度

安装

如果您的发行版未包含 GNU Parallel,您可以进行个人安装,此操作无需 root 访问权限。只需 10 秒即可完成,操作如下:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

对于其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README

了解更多

查看更多示例:http://www.gnu.org/software/parallel/man.html

观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

完成教程:http://www.gnu.org/software/parallel/parallel_tutorial.html

注册电子邮件列表以获取支持:https://lists.gnu.org/mailman/listinfo/parallel

答案3

如果您不需要 选项-Pxargs那么您可以使用find -execdir选项,它类似于-exec但在执行之前会cd进入目录。示例:https://stackoverflow.com/questions/16541582/finding-multiple-files-recursively-and-renaming-in-linux/54163971#54163971

相关内容