如何修复不正确的 gnu 并行子字符串提取

how to fix incorrect gnu parallel substring extraction

我尝试在 bash 脚本中使用子字符串提取与 gnu 并行。但是下面的代码(从更复杂的案例中简化而来)产生了错误的结果。

#!/bin/bash                                                        

function foo(){                                                    
  echo "${1:0:1} ${1:1:1}" # substring extraction                  
}                                                                  

function bar(){                                                    
  IFS=', ' read -r -a array <<< "" # string to array conversion
  echo "${array[0]} ${array[1]}"                                   
}                                                                  

export -f foo                                                      
export -f bar                                                      

values=( '12' '34' )                                               

parallel echo $(foo {} ) ::: "${values[@]}"                        
# produces wrong output...                                         
# {} 12                                                            
# {} 34                                                            

parallel echo $(bar {} ) ::: "${values[@]}"                        
# produces wrong output...                                         
# 12                                                               
# 34   

你能给我一些提示吗,我怎样才能说服 gnu parallel 假设函数内部的一个变量存在,而不是只有括号。

我认为您缺少的是 bash 将在 $(foo {} ) 将参数传递给 parallel 之前 进行进程替换。如果将 parallel 替换为 printf "%s\n":

就可以看到这一点
printf "%s\n" echo $(foo {} ) ::: "${values[@]}"
echo
{
}
:::
12
34

这意味着您的命令等同于:

parallel echo { } ::: 12 34

这就是为什么它打印 { } 12{ } 34 的原因。这里没有 {}parallel 替换,因为 foo 已将其拆分为两个单独的参数,{}。所以就像 xargs 在没有 {} 时所做的那样,parallel 只是将 args 添加到命令的末尾,产生命令:

echo { } 12
echo { } 34

要延迟进程替换,需要用单引号括起来:

parallel echo '$(foo {} )' ::: "${values[@]}"

然而,这会导致另一个问题,因为 parallel 生成的进程无法识别函数 foo。但是你可以用 export -f:

来解决这个问题
export -f foo
parallel echo '$(foo {} )' ::: "${values[@]}"
1 2
3 4

您的 bar 示例也是如此。

编辑:您的 bar 示例仍然打印与之前相同的内容,但出于不同的原因。您正在尝试将 read bar 的第一个参数转换为 array,使用 IFS=', ',但您的输入不包含任何逗号(或空格),因此您得到每次一个元素的数组,array[1] 展开为空。

但是,如果您改为这样做,它会起作用(或者至少我 认为 会起作用 - 我不确定您对这个示例的预期输出是什么):

values=( "1,2" "3,4" )
parallel echo '$(bar {} )' ::: "${values[@]}"
1 2
3 4