bash命令的并行执行

时间:2019-01-29 16:04:18

标签: bash parallel-processing xargs gnu-parallel

我有一个bash脚本,它具有一个循环,其中有一个bash命令,该命令调用另一个bash脚本,而该bash脚本又调用python脚本。

循环中的每个bash命令都可以彼此独立运行。当我以后在实际的数据集上运行它时,执行每个命令需要一些时间。因此,我想利用并并行化脚本的这一部分。

我花了几天时间查看bash中执行并行执行的选项,同时还给我选择了要并行化代码的内核数量,这样我就不会淹没服务器。在寻找了GNU选项之后,在我看来xargs -P似乎是最合理的,因为我不必具有特定的bash版本,并且无需安装额外的库就可以工作。但是,即使看起来很简单,我也很难使它起作用。

#!/bin/bash

while getopts i:t: option
do
case "${option}"
in
    i) in_f=${OPTARG};;
    t) n_threads=${OPTARG};;
esac
done    

START=$(date +%s)
class_file=$in_f
classes=( $(awk '{print $1}' ./$class_file))
rm -r tree_matches.txt
n="${#classes[@]}"
for i in $(seq 0  $n);
   do
     for j in $(seq $((i+1)) $((n-1)));
         do
            echo ${classes[i]}"    "${classes[j]} >> tree_matches.txt
         done
   done
col1=( $(awk '{print $1}' ./tree_matches.txt ))
col2=( $(awk '{print $2}' ./tree_matches.txt ))


printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads sh myFunction.sh -1 ${classes[k]} -2 ${classes[k]}

n_pairs="${#col1[@]}"

END=$(date +%s)
DIFF=$(( $END - $START ))
echo "Exec time $DIFF seconds"

您可以忽略最初两个嵌套循环,我只是为了完整起见粘贴了整个脚本。将要并行化的部分是从脚本结尾算起的第四行代码:

printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads sh myFunction.sh -1 ${classes[k]} -2 ${classes[k]}

因此,基本上,这将遍历所有对,在我的情况下总计为1275,并且理想情况下将使用变量与指定数量的线程并行执行myFunction.sh:     $ n_threads

但是我做错了什么,因为该行中的迭代器k没有索引我的两个数组    $ {classes [k]} 和    $ {classes [k]} 循环保持迭代1275次,但仅在我回显它们时才索引两个数组的第一个元素。后来我将该行更改为此行以进行故障排除:

printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads echo "index" k

实际上,每次循环它都会递增k的值,但是当我将该行更改为此时:

printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads echo "index" "$((k))"

打印出0,是k的值1275倍。我不知道我在做什么错,我很确定但是应该是一些语法错误。任何指导将不胜感激。非常感谢。

更新!

我实际上有两个向量,它们的大小相同,并输入了myFunction.sh脚本。我只希望整数索引能够同时对它们进行idnex并使用从这两个向量中索引的这两个值来调用我的函数。根据您的建议,我对代码进行了如下修改:

 for x in {0..10};
    do
        printf "%d\0" "$x"; done| xargs -0 -I @@ -P $n_threads sh markerGenes2TreeMatch.sh -1 ${col1[@@]}-2 ${col2[@@]}

但是现在执行代码时,出现以下错误:

@@: syntax error: operand expected (error token is "@@")

我猜这个索引'@@'仍然是字符串格式。我只希望在循环时生成整数索引,并且可以并行执行此命令。

3 个答案:

答案 0 :(得分:1)

有关行:

http://example.com/static/img/admin/...

printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads sh myFunction.sh -1 ${classes[k]} -2 ${classes[k]} 将在xargs看到它之前被shell扩展(几乎没有可能)。

也许您可以重新排序:

${classes[k]}

答案 1 :(得分:0)

此行不起作用,如您所想:

ggplot

发生的事情是BASH首先将printf "%s\0" {0..1275} | xargs -0 -I k -P $n_threads sh myFunction.sh -1 ${classes[k]} -2 ${classes[k]} $n_threads之类的内容扩展为字符串,然后调用${classes[k]}。顺便说一句。由于键xargs不在数组${classes[k]}中,因此""始终为"k"。尝试classes;然后BASH将首先替换变量${classes[$k]},然后使用结果在k中查找值。

也许更好的方法是将classes中的值写入文件,并将其用作classes的输入。您可能需要更改xargs才能接受单个参数(=输入一行)并将其在脚本中分解。

答案 2 :(得分:0)

使用GNU Parallel,您可能可以做到:

classes=( $(awk '{print $1}' ./$class_file))
parallel markerGenes2TreeMatch.sh -1 {=1 'if($arg[1] ge $arg[2]) { skip() }' =} -2 {2} ::: ${classes[@]} ::: ${classes[@]}

或:

parallel --plus markerGenes2TreeMatch.sh -1 {1choose_k} -2 {2choose_k} ::: ${classes[@]} ::: ${classes[@]}

然后,您可以跳过一整代的tree_match.txt和$ col1 / $ col2。

使用parallel --embed直接在脚本中包含GNU Parallel,因此您没有外部依赖项。