Home > Software design >  bash parse options from string created in other method
bash parse options from string created in other method

Time:09-16

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.

CodePudding user response:

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

CodePudding user response:

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[@]}"
  •  Tags:  
  • bash
  • Related