3

I want to create a BASH script that calls another script or command as a wrapper. Calling arguments should be collect passed with one exception. How to filter a special argument name value pair?

Like for example when i call the first script with argument count X=$#:

$ ./foo.sh -v --first val1 ... --argname 'value with spaces' ... --last val3

It should then call a second command or script with new argument count X'=X-2 :

$ ./bar.sh -v --first val1 ... --last val3

2 Answers 2

9

There could be reasons you want the removal to happen in a function, but your attempt seems excessively complex as well as insecure and opaque in that it doesn't just filter an array.

args=("$@")
for ((i=0; i<"${#args[@]}"; ++i)); do
    case ${args[i]} in
        --argname) unset args[i]; unset args[i+1]; break;;
    esac
done
./bar.sh "${args[@]}"
Sign up to request clarification or add additional context in comments.

2 Comments

this showed easy way to parse for extra arguments after a -- for ((d=1; d<$#; ++d)); do; [[ ${!d} == "--" ]] && break; done; extraargs=("${@:$d+1:$#}")
Or just add --) break;; to the existing case statement.
0

I came up with this solution for foo.sh :

#!/bin/bash

echo "executing foo.sh:"

function arg_remove ()
{
    local array=("${@:3}")

    for ((i=0; i<"${#array[@]}"; ++i)); do
        case ${array[i]} in
            "$2") unset array[i]; unset array[i+1]; break ;;
        esac
    done

    # clean up unset array indexes
    for i in "${!array[@]}"; do
        new_array+=( "${array[i]}" )
    done
    array=("${new_array[@]}")
    unset new_array

    # assign array outside function scope
    local -g "$1=(  )"
    eval ${1}='("${array[@]}")'
}

echo "arguments income :" "$@"
arg_remove ARG_PASS '--argname' "$@"
echo "arguments passed :" "${ARG_PASS[@]}"

./bar.sh "${ARG_PASS[@]}"

The second output test script will only print all passed arguments grouped line by line bar.sh :

#!/bin/bash

echo "executing bar.sh:"

while [[ $# -gt 0 ]]
do
    key="$1"

    if [[ "$key" == --* ]]; then
        shift
        echo $key $1
    else
        echo $key
    fi
    shift
done

Now calling the first script results in:

$ ./foo.sh -v --first val1 --argname 'value with spaces' --last val3
executing foo.sh:
arguments income : -v --first val1 --argname value with spaces --last val3
arguments passed : -v --first val1 --last val3

executing bar.sh:
-v
--first val1
--last val3

You can also simplify the code and remove the separation of function arg_remove and clean up so you get a minimalistic version of foo_mini.sh without the need for eval:

#!/bin/bash

args=("${@}")
filter="--argname"

for ((i=0; i<"${#args[@]}"; ++i)); do
    case ${args[i]} in
        "$filter") unset args[i]; unset args[i+1]; break ;;
    esac
done

./bar.sh "${args[@]}"

4 Comments

the last line is passing only one argument
The code in this answer is not corrected, it still passes a single argument to bar.sh. Why is this only processing "${@:3}" and why are you copying the array instead of just modifying it in place? ... Though none of that makes a difference if you don't use the array when passing on the result.
@tripleee thank you, now the example is completed and tested
I'll still caution against using eval for anything unless you know exactly what you are passing in to it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.