GNU parallel 忽略管道命令

GNU parallel ignores piped commands

我最终尝试使用并行作为一个简单的作业队列管理器,la here。这个想法似乎是将命令放在一个文件中,让 tail 读取文件(使用 -f 选项以便它不断寻找新行),然后将 tail 的输出通过管道传输到并行文件中。所以我试试

true > jobqueue; tail -n+0 -f jobqueue | parallel
echo echo {} ::: a b c >> jobqueue

但是没有任何反应。好的...测试一下,然后我就试试

cat jobqueue | parallel

这给出了

{} ::: a b c

同时

parallel echo {} ::: a b c

正确输出

a
b
c

那么,为什么 parallel 在从文件输入时忽略类似并行的语法,但在直接给出命令时却运行良好?

FWIW 这是版本 20160722,由于我在机器上没有 root 访问权限,所以我必须从源代码构建并安装到我的主目录中。

So why does parallel ignore the parallel-ish syntax when it was fed from a file, but runs fine when it's given the command directly?

因为这是规定要做的。您描述为 "syntax" 的内容在手册中定义为各种 命令行参数 及其部分。这些似乎主要针对在 parallel 的命令行上给出并行化命令并且程序输入由要操作的数据组成的情况。这是 xargs 程序的操作模式,它是 parallel.

的灵​​感之一

事实是,你让事情变得比他们需要的更复杂。当您 运行 parallel 没有在其命令行上指定命令时,您通过其输入输入的命令不需要 需要 那种输入行操作parallel 本身提供的操作,一般来说,除了在它们自己的命令行上之外,它们不能以任何其他方式获取参数。当您 运行 parallel 处于该模式时,您只需向它提供您想要的确切命令 运行:

true > jobqueue; tail -n+0 -f jobqueue | parallel
echo echo a b c >> jobqueue

true > jobqueue; tail -n+0 -f jobqueue | parallel
echo echo a >> jobqueue
echo echo b >> jobqueue
echo echo c >> jobqueue

,取决于你到底在追求什么。

至于当您使用 tail -fparallel 提供输入时似乎没有任何反应,我倾向于认为 parallel 正在等待更多输入。它的第一次读取没有 return 足够的数据来触发它调度任何作业,但标准输入仍然打开,因此它有理由认为会有更多的输入(这确实是合适的)。如果您继续为它提供作业,那么它很快就会获得足够的输入来开始 运行 处理它们。当您准备好关闭队列时,您必须 kill tail 命令以便 parallel 知道它已到达其输入的末尾。

来自man parallel

There is a a small issue when using GNU parallel as queue system/batch manager: You have to submit JobSlot number of jobs before they will start, and after that you can submit one at a time, and job will start immediately if free slots are available. Output from the running or completed jobs are held back and will only be printed when JobSlots more jobs has been started (unless you use --ungroup or -u, in which case the output from the jobs are printed immediately). E.g. if you have 10 jobslots then the output from the first completed job will only be printed when job 11 has started, and the output of second completed job will only be printed when job 12 has started.

我已经设法拼凑出一个(充分)适用于我的情况的解决方案,这是对@John Bollinger 的回答的详尽阐述。

关键是我想将两个命令 的参数通过管道传递给 parallel,并且这些参数会超过某个范围。例如,运行 command1 x 其中 x 范围超过 1..100。现在 parallel 有一个有效的内置语法,即

parallel command1 ::: {1..100}

如果这就是我想做的,那很好。但我也有 command2command3 等等,每个参数都有范围,我想将所有这些输入 parallel 进行管理。我希望能够在我已经开始后添加更多命令 运行 parallel.

使用 tail 连续读取一些文件 jobqueue 正如我在问题中提出的那样,作为一个作业队列。要让 tailparallel 在某些特殊字符串 endoffile 上退出,我使用

tail -f jobqueue | while read LINE
do
    echo $LINE
    [[ $LINE == *endoffile* ]] && pkill -P $$ tail
done | parallel -u -E endoffile

然后可以将命令输入 jobqueue,但 ::: 语法不再有效。如果我们以老式的方式做,事情确实有效:

for i in {1..100}
do
    echo command1 $i >> jobqueue
done

然后最后事情可以用echo endoffile >> jobqueue结束。