使用 GNU Parallel 中的每个输入参数作为工作目录

使用 GNU Parallel 中的每个输入参数作为工作目录

我尝试使用 GNU Parallel 为每个输入参数运行命令,使用该参数作为命令的工作目录(不将其附加到命令行)。

基本上,我需要做的是:

/foo -> "cd /foo; mycmd"
/bar -> "cd /bar; mycmd"
/baz -> "cd /baz; mycmd"

Parallel has--workdir似乎可以通过支持{}替换字符串来实现我想要的功能:

--workdir mydir
--wd mydir

作业将在目录 mydir 中运行。默认值是本地计算机的当前目录,以及远程计算机的登录目录。
<...>
mydir 可以包含 GNU Parallel 的替换字符串。

为了防止参数被附加到命令行,我尝试使用-n0or -N0

--max-args 最大参数
-n 最大参数

每个命令行最多使用 max-args 个参数。
<...>
-n 0 表示读取一个参数,但在命令行上插入 0 个参数。

然而,这似乎不起作用:

$ mkdir -p $HOME/{foo,bar,baz}
$ printf '%s\n' $HOME/{foo,bar,baz} | parallel --workdir '{}' -n0 'pwd'
parallel: Error: Cannot change into non-executable dir : No such file or directory

请注意 之前的空格:,这不是 GNU 并行中的拼写错误,而是表明 workdir 被评估为空字符串。如果我在 前面添加一个固定字符串{},这一点就会变得很明显,在这种情况下,所有 pwd 都会打印该固定字符串:

$ printf '%s\n' $HOME/{foo,bar,baz} | parallel --workdir '/{}' -N0 'pwd'       
/
/
/

我究竟做错了什么?

答案1

我相信最简单的是:

printf '%s\n' $HOME/{foo,bar,baz} | parallel 'cd {} && myprg'

使用--workdir,但它显然不适用于这种情况。 GNU Parallel 通常需要在命令模板中使用替换字符串,并且您希望{}包含 的参数--workdir

使用-n0不会有帮助,因为 then{}将为空,然后--workdir会失败:{}无论在何处使用,计算结果都是相同的字符串。

所以解决方法是使用{},但在没有危害的地方使用它:

parallel --workdir {} 'true dummy {}; myprg' ::: $HOME/{foo,bar,baz}

或者使用{==}生成命令的静态部分:

parallel --workdir {} '{= $_="myprg" =}' ::: $HOME/{foo,bar,baz}

就我个人而言,我更喜欢这个cd {}版本:我认为更容易看到你正在尝试做什么。

答案2

AFAICT--workdir并不意味着{...}扩展其论点中的所有指令。不管怎样, GNUparallel都会运行一个 shell 来解释你给出的代码,所以你总是可以这样做:

... | PARALLEL_SHELL=sh parallel 'CDPATH= cd -P -- {} && mycmd'

(这里强制 shellsh而不是依赖 的parallel启发式方法来确定要运行哪个 shell,并解决 的一些问题cd

如果您不需要 GNU 的任何功能parallel,您可以将 GNUxargs与 GNU 结合使用env,避免 GNUparallel和 shell 开销以及不可靠的cdshell 内置:

... | xargs -rd '\n' -P8 -I{} env -C {} mycmd

相关内容