| Chris F.A. Johnson 2007-10-25, 1:32 am |
| 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<property>=<value> 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<property>=<value> 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 # <prop>=<value>
> 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<p>=<v> ), 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 <http://cfaj.freeshell.org/shell/>
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
|