1

So,

I've figured out thus far how to utilize the "local -n " command, which effectively allows me to "reference pass" a variable from one function to another.

this is rather helpful when parsing out $[#] parameters that could be in any order.

if %1 is always the same thing this isn't a problem, but (for example):

git checkout -b --track MyBranch

is the same as

git checkout --track -b MyBranch

however, in the concept of a hypothetical 'git' function checkout, -b, --track, and MyBranch are simple %1, %2, %3 and %4 which means the function needs to be smart enough to interpret which one is which.

In solving this riddle, and to expand my bash scripting knowledge, i starting working with the local -n command and created a function like this:

parseParam %1 -d opt -c opt "%" name
parseParam %2 -d opt -c opt "%" name
parseParam %3 -d opt -c opt "%" name

"parseParam" simply evaluates the first parameter (the passed %[#]) and compares to parameters 2,4,6 (% is the moniker for just a string no - or / prefix), and on a match uses the local -n on parameter 3, 5, and 7 for assignment. The calling function can then access $opt or $name without concern for the originating $[#] parameter.

This works find. However, as you can see the impending flaw in the above calling convention, that if both -d and -c were provided the calling function, then after executing the "parseParam" the last provided parameter would be assigned to "opt".

I have tried two solutions, one worked, one however (the cleaner one) did not.

parseParam $1 "%" name -c opt -d opt -s opt -m msg
if [[ $? -ge 2 ]] && [[ $? -le 4 ]]; then
    parseParam $2 "%" name -m msg
else parseParam $2 "%" name -c opt -d opt -s opt -m msg
fi;
if [[ $? -ge 2 ]] && [[ $? -le 4 ]]; then
    parseParam $3 "%" name -m msg
else parseParam $3 "%" name -c opt -d opt -s opt -m msg 
fi;

That functional version is great for a single parameter issue. That flow says that -c, -d, or -s may be used as parameters, but only one is accepted. but if I had a "name" and a "target" parameter, this flow would get insanely complex and effectively would defeat the purpose of the parseParam. So I tried a different tact:

parm="\"%\" name -c opt -d opt -s opt -m msg"

parseParam $1 $parm
cleanParam $? parm $parm 

so parseParm would execute the same but the list of parameters would be provided by $parm variable. CleanParam as you could expect would remove parameter optiosn form the $parm variable based upon which one was populated (as returned by the parseParam function).

However, even though parseParam interpreted 11 parameters, and individually recognized each one, the local -n command failed to transcend the function boundary when executing parseParam in this manner. So, inside parseParam $opt would return -d, but once back in the calling function $opt would still be empty. if I pass the parameters individually it works, but if I pass them as a single string they don't.

So after all that preamble, my question is:

Is there a way to pass a list from from one function to another:

parseParam $! $listOfParameters $listOfVariableNames

So that parseParam, when processing the variable names can assign a value to that name (like withe local -n) that will be accessible from the calling function.

Thanks Jaeden "Sifo Dyas" al'Raec Ruiner

Current function defs for reference:

#======================================
# ParseParam function
#======================================

parseParam()
{
    p=$1;
    shift;
    l=$#;
    # echo "Param Count : $l, $p"
    if [ $((l%2)) -eq 0 ]; then
        paramType $p $1 $3 $5 $7 $9
        idx=$?
        if [[ $idx -gt 0 ]]; then
            shift $(( ($idx - 1) * 2 ))
            # echo "Index: $idx - $1 = $2"
            local -n var="$2"
            if [[ ${p:2:1} = "=" ]]; then var=${p:3}; 
            elif [[ $p == /* ]] || [[ $p == -* ]]; then var=${p:1:1};
            else var=$p;
            fi;
            # echo "Var = $var, $opt"
            return $idx;
        fi;
    fi;
    return 0;
}

#======================================
# ParamType function
#======================================

paramType() 
{
    ret=0;
    p=$1; 
    shift;
    while [ "${1+defined}" ]; do
        let ret+=1
        l=${#1}
        if ([[ $p == /* ]] || [[ $p == -* ]]) && ([[ $1 == /* ]] || [[ $1 == -* ]]) && [[ ${p:1:1} = ${1:1:1} ]]; then 
            return $ret
        elif [[ $p != /* ]] && [[ $p != -* ]] && [[ $1 = "%" ]]; 
            then return $ret;
        fi;
        shift
    done
    return 0;
}
  • Have you considered using getopts? – boardrider Dec 12 '15 at 12:55
  • no. did not know of it. looking it up now. thanks. – JaedenRuiner Dec 14 '15 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.