-1

I have a function that takes arguments in different combinations. How they are setup depends on other conditions so I created a method to set them up.

#!/bin/bash

myFunc() {
    while getopts m:t::T::rp:: arg; do
        case "$arg" in
            m)  log_msg="$OPTARG";;
            t)  timeout="$OPTARG";;
            T)  timeout_msg="$OPTARG";;
            r)  retry="yes";;
            p)  postpone="$OPTARG";;
            *)  die "invalid arguments $*";;
        esac
    done

    #doStuff...
}

setupOpts() {
    local name="$1"
    local param="$2"
    local err_msg="$3"
    if someTest "$name"; then
        # case all
        echo "-t 9 -T "$err_msg" -p "$name" -r"
    elif someOtherTest "$name" "$param"; then
        echo "-t 120 -T "$err_msg" -p "$name""
    else
        echo "-t 300 -T "$err_msg""
    fi
}

mainFunc() {
   # some stuff...
   opts="$(setupOpts "$someName" "$someParam" "Some Err Msg")"
   myFunc -m "Some Msg" "$opts"
}

I not manage to get this working. E.g. when case all (see comment in code) is true:

opts="$(setupOpts "peter-pan" "$someParam" "Some Err Msg")"
# -> results in: myFunc -m "some Msg" -t 9 -T "Some Err Msg" -p "peter-pan" -r

However, the arguments behind -t and following are not parsed corretly. I guess it has something to do with quoting and word splitting.

Depending on quotes:

myFunc -m "Some Msg" "$opts":

timeout=9 -T "Some Err Msg" -p "peter-pan" -r
timeout_msg=
postpone=
retry=

or

myFunc -m "Some Msg" $opts:

timeout=9
timeout_msg=Some
postpone=
retry=

Correct would be

timeout=9
timeout_msg=Some Err Msg
postpone=peter-pan
retry=yes

I have tried different other things like using escaped quotes (echo "-t 9 -T "\"Some Err Msg\"" -p "$argOne" -r") or using echo without surrounding quotes.

Is this somehow doable using bash or am I hitting a limit here?

PS: Setting things up in myFunc would work as well but that's not the solution to my answer. I would like to know if this approach would work with bash somehow.

5
  • please update the question with the details to reproduce your issue, for starters: the definitions of someTest and someOtherTest Commented Sep 12, 2021 at 17:04
  • Both are functions that check certain conditions and return 0/1 depending on that conditions, e.g. if a vm can be redeployed. I don't see how the exact definition of them would serve the question. The output of setupOpts() should change depending on what condition is true or default to the else part. You can use any test for that, e.g. if the name is a certain string. Commented Sep 12, 2021 at 17:41
  • yes, I understand what the functions are supposed to do; I was pointing out that it's harder for people to reproduce the issue let alone come up with suggested solutions when the sample code fails to run (in our environments); regardless, assuming setupOpts() is functioning as expected and the only issue is with the quoting/word-splitting when calling myFunc() ... my answer addresses this issue; alternatively ... Commented Sep 12, 2021 at 19:05
  • a google search on bash command line args as array brings up many hits on this topic, eg, this and this Commented Sep 12, 2021 at 19:06
  • Thanks for your support. I will take your point into account and post an copy/paste example next time. Regarding the google search: I did an extensive search but didn't find anything that would work but I found some hints that it might not even work due to bash limitations. I didn't search for bash command line args as array since I didn't have that idea and thus posted this question to ask if it is even possible (see PS). And as you can see from the accepted answer simply turning the args into an array doesn't worked, I needed to combine it with a nameref. Commented Sep 13, 2021 at 10:38

2 Answers 2

2

Due to complexities of quoting, you can use nameref combined with arrays :

#!/usr/bin/env bash

myFunc() {
    while getopts m:t::T::rp:: arg; do
        case "$arg" in
            m)  log_msg="$OPTARG";;
            t)  timeout="$OPTARG";;
            T)  timeout_msg="$OPTARG";;
            r)  retry="yes";;
            p)  postpone="$OPTARG";;
            *)  die "invalid arguments $*";;
        esac
    done

    #doStuff...
}

setupOpts() {
    local name="$1"
    local param="$2"
    local err_msg="$3"
    declare -n inner_opts=$4
    if someTest "$name"; then
        # case all
        inner_opts=(-t 9 -T "$err_msg" -p "$name" -r)
    elif someOtherTest "$name" "$param"; then
        inner_opts=(-t 120 -T "$err_msg" -p "$name")
    else
        inner_opts=(-t 300 -T "$err_msg")
    fi
}

mainFunc() {
   # some stuff...
   local outer_opts
   setupOpts "someName" "someParam" "Some Err Msg" outer_opts
   myFunc -m "Some Msg" "${outer_opts[@]}"
}

mainFunc
Sign up to request clarification or add additional context in comments.

Comments

0

Without the definitions of someTest and someOtherTest I'm unable to reproduce OP's output so fwiw ...

It looks (to me) like the setupOpts() function generates a set of command line options that are to be passed to the myFunc() function. Assuming setupOpts() generates the correct output, I'm guessing one solution would be store the output from setupOpts in an array, eg:

opts=( $(setupOpts "peter-pan" "$someParam" "Some Err Msg") )

The main call to myFunc() then becomes:

myFunc -m "Some Msg" "${opts[@]}"

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.