我尝试使用 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 的替换字符串。
为了防止参数被附加到命令行,我尝试使用-n0
or -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 开销以及不可靠的cd
shell 内置:
... | xargs -rd '\n' -P8 -I{} env -C {} mycmd