Dmitry Petrov Dmitry Petrov - 4 months ago 9
Bash Question

Change function arguments in Bash

I'd like to change function arguments before passing them to a next function.

firstfunction() {
# change "-f" to "--format" in arguments
secondfunction "$@"
}


I tried to convert to an array, change the array and convert back to arguments. But it looks so complicated. Is it possible to make it simpler?

UPDATE: to be more specific...

firstfunction data.txt -f "\d+"


should call

secondfunction data.txt --format "\d+"

Answer

This is a surprisingly tough problem. Bash is simply not very good at working with (slightly) complex data structures like arrays.

I think the only conceivable robust solution will require a loop. This is the easiest way I can think of:

function firstfunction {
    local -A map=(['-f']='--format');
    local -a args=();
    for arg in "$@"; do
        if [[ -v map[$arg] ]]; then
            args+=("${map[$arg]}");
        else
            args+=("$arg");
        fi;
    done;
    echo ${args[@]+"${args[@]}"}; ## replace echo with secondfunction to run
};
firstfunction;
##
firstfunction a b;
## a b
firstfunction x -f -fff -f-f -fxy x-f \ -f -f\  -f;
## x --format -fff -f-f -fxy x-f  -f -f  --format

Using ${args[@]+"${args[@]}"} instead of just "${args[@]}" for the final expansion works around the ill-advised design decision the bash developers made to reject an empty array as an "unbound variable" if you have the nounset set option (set -u) enabled. See Bash empty array expansion with `set -u`.