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

时间:2019-03-14 23:29:15

标签: bash gnu-parallel

我尝试在与gnu parallel混合的bash脚本中使用子字符串提取。但是下面的代码(从更为复杂的情况简化)会产生错误的结果。

#!/bin/bash                                                        

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

function bar(){                                                    
  IFS=', ' read -r -a array <<< "${1}" # 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假设函数内部存在一个变量而不是方括号。

1 个答案:

答案 0 :(得分:2)

我认为您所缺少的是,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示例的打印内容与以前一样,只是出于不同的原因。您尝试使用readbar的第一个参数array插入IFS=', ',但是您的输入不包含任何逗号(或空格),因此得到每次由一个元素组成的数组,并且array[1]扩展为空。

但是,如果您改为执行此操作,则它可以工作(或者至少我认为它可以工作-我不确定此示例的预期输出是什么):

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