bashshxargs

Calling shell functions with xargs


I am trying to use xargs to call a more complex function in parallel.

#!/bin/bash
echo_var(){
    echo $1
    return 0
}
seq -f "n%04g" 1 100 |xargs -n 1 -P 10 -i echo_var {} 
exit 0

This returns the error

xargs: echo_var: No such file or directory

Any ideas on how I can use xargs to accomplish this, or any other solution(s) would be welcome.


Solution

  • Exporting the function should do it (untested):

    export -f echo_var
    seq -f "n%04g" 1 100 | xargs -n 1 -P 10 -I {} bash -c 'echo_var "$@"' _ {}
    

    You can use the builtin printf instead of the external seq:

    printf "n%04g\n" {1..100} | xargs -n 1 -P 10 -I {} bash -c 'echo_var "$@"' _ {}
    

    Also, using return 0 and exit 0 like that masks any error value that might be produced by the command preceding it. Also, if there's no error, it's the default and thus somewhat redundant.

    @phobic mentions that the Bash command could be simplified to

    bash -c 'echo_var "{}"'
    

    moving the {} directly inside it. But it's vulnerable to command injection as pointed out by @Sasha.

    Here is an example why you should not use the embedded format:

    $ echo '$(date)' | xargs -I {} bash -c 'echo_var "{}"'
    Sun Aug 18 11:56:45 CDT 2019
    

    Another example of why not:

    echo '\"; date\"' | xargs -I {} bash -c 'echo_var "{}"'
    

    This is what is output using the safe format:

    $ echo '$(date)' | xargs -I {} bash -c 'echo_var "$@"' _ {}
    $(date)
    

    This is comparable to using parameterized SQL queries to avoid injection.

    I'm using date in a command substitution or in escaped quotes here instead of the rm command used in Sasha's comment since it's non-destructive.