Reputation: 1689
I've tried to use substring extraction in bash script mixed with gnu parallel. But below code (simplified from much more complicated case) produces wrong results.
#!/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
Could you provide me some hint how can I convince gnu parallel to assume that a variable inside function exists and are not ony brackets.
Upvotes: 1
Views: 323
Reputation: 4612
I think what you're missing is that bash
will do the process substitution $(foo {} )
before it passes arguments to parallel
. You can see this if you replace parallel
with printf "%s\n"
:
printf "%s\n" echo $(foo {} ) ::: "${values[@]}"
echo
{
}
:::
12
34
Which means your command is equivalent to this:
parallel echo { } ::: 12 34
And hence why it prints { } 12
and { } 34
. There is no {}
here for parallel
to replace, since foo
has split it into two separate args, {
and }
. So just like xargs
does when there's no {}
, parallel
just tacks on the args to the end of the command, yielding the commands:
echo { } 12
echo { } 34
To delay the process substitution, you need to wrap it in single quotes:
parallel echo '$(foo {} )' ::: "${values[@]}"
However, this leads to another problem, because the process spawned by parallel
won't recognize function foo
. But you can solve that with export -f
:
export -f foo
parallel echo '$(foo {} )' ::: "${values[@]}"
1 2
3 4
Likewise for your bar
example.
Edit: Your bar
example still prints the same as it did before, but for a different reason. You're trying to read
the first argument to bar
into array
, with IFS=', '
, but your input doesn't contain any commas (or spaces), so you get an array of one element each time, and array[1]
expands to nothing.
But if you do this instead, it works (or at least I think it does - I'm not sure what your expected output was for this example):
values=( "1,2" "3,4" )
parallel echo '$(bar {} )' ::: "${values[@]}"
1 2
3 4
Upvotes: 2