我试图在与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并行假设函数内部存在变量并且不是ony括号。
我认为你缺少的是bash
会在将参数传递给$(foo {} )
之前进行过程替换parallel
。如果用parallel
替换printf "%s\n"
,你可以看到这个:
printf "%s\n" echo $(foo {} ) ::: "${values[@]}"
echo
{
}
:::
12
34
这意味着你的命令等同于:
parallel echo { } ::: 12 34
因此它打印{ } 12
和{ } 34
的原因。这里没有{}
替换parallel
,因为foo
将它分成两个独立的args,{
和}
。就像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