多个(有一个固定的)GNU 并行参数

Multiple (with one fixed) GNU-parallel arguments

我使用 GNU-parallel 重复调用函数 foo。该函数有两个参数,一个文件名(下面示例中的 a,保存在数组 A 中)和一个过滤器数组(下面的 B,以 b 作为元素B).

该函数应该遍历 AB 的所有组合,但是,要注意的是,我实际上仅使用并行来遍历 A,同时提供 B 到每个函数调用。

举个最简单的例子:

#!/bin/bash

A=("1" "2" )
B=("X" "Y")

foo() {
    a= # a single element of A
    B= # the whole array B
    for b in "${B[@]}"; do
        printf "a = %s; b = %s\n" $a $b
    done
    echo "-----------------"
}
export -f foo

# goal:
echo "Sequential (aka, the target) ==="
for a in "${A[@]}"; do
    foo $a $B
done

结果

Sequential (aka, the target) ===
a = 1; b = X
a = 1; b = Y
-----------------
a = 2; b = X
a = 2; b = Y
-----------------

请注意,我们不是对每个组合都进行一次调用,而是对每个 A 进行一次调用,然后在函数内迭代 B.

并行尝试:

尝试 1

parallel foo ::: "${A[@]}" ::: "${B}"

结果

a = 1; b = X
-----------------
a = 2; b = X
-----------------

(缺少 B 的第二个参数)

尝试 2

parallel foo ::: "${A[@]}" ::: "${B[@]}" 

结果

a = 1; b = X
-----------------
a = 1; b = Y
-----------------
a = 2; b = X
-----------------
a = 2; b = Y
-----------------

(每个组合调用一次,而不是每个 A 调用一次,然后迭代 B)

我已经查看了手册和 SO,但找不到解决方案。

编辑

感觉直接导出数组B应该可以,但是也没有结果

foo2() {
    a= # a single element of A
    # B= # the whole array B
    for b in "${B[@]}"; do
        printf "a = %s; b = %s\n" $a $b
    done
    echo "-----------------"
}
export -f foo2
export B

parallel foo ::: "${A[@]}"

结果

-----------------
-----------------

(显然是空B)

您的问题源于 B 是一个数组。我以前从未见过将数组作为参数传递给函数,我不确定是否可以做到。

第二个问题是,虽然您可以导出函数和变量,但您不能不作弊地导出数组:Exporting an array in bash script

GNU Parallel 使使用 env_parallel 作弊变得容易。这会将完整环境导出到 shell 运行 命令:数组、变量、别名和函数。它甚至会在 运行 远程命令时这样做。

env_parallel 去年进步很大,如果你的版本有问题请升级。

#!/bin/bash                                                                        

A=("1" "2" )
B=("X" "Y")

foo() {
    a= # a single element of A                                                   
#    B= # the whole array B                                                      
    for b in "${B[@]}"; do
        printf "a = %s; b = %s\n" $a $b
    done
    echo "-----------------"
}

# If you have earlier run 'env_parallel --install'                                 
# to activate env_parallel in your shell                                           
# this should work.                                                                
env_parallel foo ::: "${A[@]}"

# If you have not, then this should work:
. `which env_parallel.bash`
env_parallel foo ::: "${A[@]}"