ksh parsing arguments in a string rather than from the cmdln

Hi. I have a piece of code that reads and parses command line options. I'd like to alter it slightly to read from a string (that's set elsewhere in the script) rather than directly from the command line (arg). Can somebody show me how to do this? Many thanks.

My code is as follows:

typeset flags_args=''
for arg; do
    case $arg in
        -version )  flags_args="${flags_args} -t" ;;
        -host ) flags_args="${flags_args} -r" ;;
        -debug ) flags_args="${flags_args} -d" ;;
        * )       flags_args="${flags_args} $arg" ;;
    esac
done
set -- ${flags_args}

while getopts :t:r:d args; do
    case $args in
        t) typeset VERSION="$OPTARG" ;;
        r) typeset HOST="$OPTARG" ;;
        d) typeset DEBUG="true"; typeset DEBUG="DEBUG" ;;
        *) print "Invalid option specified." ;;
    esac
done
shift $((OPTIND-1));

Instead of reading the arguments from command line I'd like the code to read from the following variable that's set inside the KSH script:

STR="-version 99 -host testhost "

or

STR="-version 99 -host testhost -debug"

Many versions of the Korn shell include a getopts that supports both long options and short options (although support for long options isn't always mentioned in the ksh man page). If you could introduce your long options with -- instead of a single - , you might want to try the following replacement for your code:

while getopts ':t:(version)r:(host)d(debug)' args; do
    case $args in
        t) typeset VERSION="$OPTARG" ;;
        r) typeset HOST="$OPTARG" ;;
        d) typeset DEBUG="DEBUG" ;;
        *) print "Invalid option specified." ;;
    esac
done
shift $((OPTIND-1));
printf 'DEBUG has been set to "%s"\n' "$DEBUG"
printf 'HOST has been set to "%s"\n' "$HOST"
printf 'VERSION has been set to "%s"\n' "$VERSION"

and see what happens when you invoke it with:

script_name --version 99 --host=testhost

and:

script_name -t 98.6 -rmyhost --debug

When I try the above two commands with ksh on macOS High Sierra (version 10.13.1), I get the output:

DEBUG has been set to ""
HOST has been set to "testhost"
VERSION has been set to "99"

and:

DEBUG has been set to "DEBUG"
HOST has been set to "myhost"
VERSION has been set to "98.6"

Thanks Don. But how do I read the parameters into that case statement from a variable set within the script rather than the command line?

Change

for arg ; do

to

for arg in $STR ; do

Beware that things like quotes-inside-quotes won't do what you want when you store arguments.

1 Like

yep ... that does the job. Many thanks.

1 Like

You can also use a subfunction to parse the command line and feed it the string:

parse_cmd ()
{
while getopts :t:r:d args; do
    case $args in
        t) typeset VERSION="$OPTARG" ;;
        r) typeset HOST="$OPTARG" ;;
        d) typeset DEBUG="true"; typeset DEBUG="DEBUG" ;;
        *) print "Invalid option specified." ;;
    esac
done
shift $((OPTIND-1));

return 0
}


...
# main()
STR="<your arguments here in the same form as parameters from stdin>"

parse_cmd $STR    # process opts and args from STR

parse_cmd $*      # process opts and args from stdin

exit 0

Note that if you use a subfunction like above you need to get the parsed values out of the function somehow, because the variables in it are now local to the function.

I hope this helps.

bakunin

Hi bakunin,
Note that typeset is not in the standards and the way it behaves varies some between shells. In bash declaring a variable with local or with typeset makes the variable definition have a scope that is local to the function and values assigned to such variables are not visible when the function returns to its caller. But, a variable that is not declared with local nor with typeset has a global scope and if such a variable is assigned a value inside a function, the value assigned in the function will still be visible when the variable is expanded outside of the function.

In ksh , declaring a variable with typeset in a function does not give it a local scope; it has a global scope. The ksh command language does not have a local keyword or built-in function.

So, in both ksh and bash , if you change:

        t) typeset VERSION="$OPTARG" ;;
        r) typeset HOST="$OPTARG" ;;
        d) typeset DEBUG="true"; typeset DEBUG="DEBUG" ;;
        *) print "Invalid option specified." ;;

in your sample to:

        t) VERSION="$OPTARG" ;;
        r) HOST="$OPTARG" ;;
        d) DEBUG="DEBUG" ;;
        *) print "Invalid option specified." ;;

The values assigned to VERSION , HOST , and DEBUG in the function parse_cmd can be found after parse_cmd completes by just expanding those variables with $VERSION , $HOST , and $DEBUG .

Note that I removed the 1st assignment to DEBUG . I don't see any reason to assign it the value TRUE and then immediately assign another value ( DEBUG ) to it.