A generic way of overriding properties declarations & definitionsat the command-line

A generic way of overriding properties declarations & definitionsat the command-line

am 25.10.2007 02:50:41 von Nicolas Girard

Hi,

I'm looking for some help with the following problem.

I would like to find a generic way of overriding declarations &
definitions of a program's properties at the command-line,
whithout interfering with the rest of the program flow.

As an example, lets us consider a bash program which declares a set of
properties prop1, prop2, ...,
and gives a default value to some of them:

#!/usr/bin/env bash
...
prop1=value1
...
[ -n "${prop2+X}" ] && echo prop2 set || echo prop2 not set
...
prop3=value3
...

Then, I would like to be able to redefine any of propN using the
following syntax:

./prog -Dprop1=myvalue1 -Dprop2

Typing the above command would make prop2 to be declared in prog, and
would give to prop1 another value than the default one.

Regarding the handling of command-line options, two important constraints
should be respected:

1. the -D= options should be mixed with the other
options controlling the program flow; thus the following example
should be valid:

./prog -u -Dprop1=myvalue1 -v=3 -Dprop2

2. even if properties names should not contain spaces, there may
be spaces in their values or elsewhere in the command-line, such
as:

./prog -u -Dprop1="/path/to my file" -v="1 2 3" -Dprop2


As for the implementation, I'd wish the -D= options to
be handled by a single, generic, resuseable function, let's call it
"parse_Dopts", transparently from the rest of the program:


#!/usr/bin/env bash
parse_Dopts $*
# rest of the program, using getopts or whatever
# to parse the command-line options
...

I came to this early implementation of parse_Dopts and I'm stuggling with
2 difficulties A and B:

function parse_Dopts()
{
local opt,prop,tmp,value
for opt in $*; do # A: what about spaces ?
if [[ ${opt:0:2} = '-D' ]]; then
tmp=${opt:2} # Suppress the leading '-D'
prop=${tmp%%=*} # Extract the property name
if [[ "${tmp}" = *=* ]]; then # =
value=${tmp##*=}
else
value=""
fi
eval $prop="$value"
else
other_options[${#other_options[@]}]="$opt"
fi
done
#set -- ${other_options[@]} # B: How to update the global positional
# parameters without leaving the
# function ?
}


The two difficulties which brought me here are:

A. right now the function does its job when its arguments don't contain
spaces, but fails otherwise ;

B. it would be very nice if the function could itself update the global
positional parameters (by removing the -D

=), so that the
rest of the program could make use of getopts without problems, in
order to process the other command-line options. But right now
I couldn't find a way of doing this *inside* the function.

Voila. I'd be grateful for *any* comments or suggestions, and thanks
anyway for reading !

Cheers,
Nicolas

Re: A generic way of overriding properties declarations & definitions at the command-line

am 25.10.2007 03:02:25 von cfajohnson

On 2007-10-25, Nicolas Girard wrote:
>
> I'm looking for some help with the following problem.
>
> I would like to find a generic way of overriding declarations &
> definitions of a program's properties at the command-line,
> whithout interfering with the rest of the program flow.
>
> As an example, lets us consider a bash program which declares a set of
> properties prop1, prop2, ...,
> and gives a default value to some of them:
>
> #!/usr/bin/env bash
> ...
> prop1=value1
> ...
> [ -n "${prop2+X}" ] && echo prop2 set || echo prop2 not set
> ...
> prop3=value3
> ...

I would use parameter expansion in my script:

prop1=${prop1-value1} ## set prop1 if not already set

Then the script could be called with:

prop1=my_value scriptname

> Then, I would like to be able to redefine any of propN using the
> following syntax:
>
> ./prog -Dprop1=myvalue1 -Dprop2
>
> Typing the above command would make prop2 to be declared in prog, and
> would give to prop1 another value than the default one.
>
> Regarding the handling of command-line options, two important constraints
> should be respected:
>
> 1. the -D= options should be mixed with the other
> options controlling the program flow; thus the following example
> should be valid:
>
> ./prog -u -Dprop1=myvalue1 -v=3 -Dprop2
>
> 2. even if properties names should not contain spaces, there may
> be spaces in their values or elsewhere in the command-line, such
> as:
>
> ./prog -u -Dprop1="/path/to my file" -v="1 2 3" -Dprop2
>
>
> As for the implementation, I'd wish the -D= options to
> be handled by a single, generic, resuseable function, let's call it
> "parse_Dopts", transparently from the rest of the program:
>
>
> #!/usr/bin/env bash
> parse_Dopts $*
> # rest of the program, using getopts or whatever
> # to parse the command-line options
> ...
>
> I came to this early implementation of parse_Dopts and I'm stuggling with
> 2 difficulties A and B:
>
> function parse_Dopts()
> {
> local opt,prop,tmp,value
> for opt in $*; do # A: what about spaces ?
> if [[ ${opt:0:2} = '-D' ]]; then
> tmp=${opt:2} # Suppress the leading '-D'
> prop=${tmp%%=*} # Extract the property name
> if [[ "${tmp}" = *=* ]]; then # =
> value=${tmp##*=}
> else
> value=""
> fi
> eval $prop="$value"
> else
> other_options[${#other_options[@]}]="$opt"
> fi
> done
> #set -- ${other_options[@]} # B: How to update the global positional
> # parameters without leaving the
> # function ?
> }
>
>
> The two difficulties which brought me here are:
>
> A. right now the function does its job when its arguments don't contain
> spaces, but fails otherwise ;
>
> B. it would be very nice if the function could itself update the global
> positional parameters (by removing the -D

=), so that the
> rest of the program could make use of getopts without problems, in
> order to process the other command-line options. But right now
> I couldn't find a way of doing this *inside* the function.

Why do you need a separate function? Just use getopts:

while getopts D:v opt
do
case $opt in
D) eval "$OPTARG" ;; ## should check that variable is a valid name
v) : ;;
esac
done

--
Chris F.A. Johnson, author
Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
===== My code in this post, if any, assumes the POSIX locale
===== and is released under the GNU General Public Licence