help-gnu-utils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: getopts - mutually exclusive flags


From: Bob Proulx
Subject: Re: getopts - mutually exclusive flags
Date: Sat, 1 Nov 2008 12:48:38 -0600
User-agent: Mutt/1.5.13 (2006-08-11)

Chris Jones wrote:
> How do I handle mutually exclusive flags with getopts?

Not seeing any other answers I might as well chime in.  I usually use
the 'getopt' way and not the 'getopts' way, because I have always used
getopt.  And the GNU version handles long options (--long-opt).  GNU
standards require long options along with --version and --help and
that pushes me to getopt.

But with getopts you should find this reference is useful:

  http://www.opengroup.org/onlinepubs/009695399/utilities/getopts.html

> But I'd like to be able to run it manually and specify via flags the
> backup I want to run - daily/incremental or monthly/full.
> 
> $ backup -d   # daily backup
> $ backup -m   # monthly ..

Sure.

> So far my best effort still finds the following acceptable:
> 
> $ backup -dm
> 
> I'm trying to use getopts to implement an exclusive OR of the two
> options.

As far as I know with all of the option parsing routines available you
would need to code this type of validation in yourself.  The
combinatorial explosion of combinations of valid and invalid options
are not something that option parsing libraries can handle.  Therefore
you need to check for validity after the options have been read.

> Incidentally, I am also curious of the "getopts" way to handle the
> absence of _any_ flags.

Again, AFAIK you would need to handle this in your code.

Here is a quick example of the way that I normally do these types of
things in my scripts.  I am cutting and pasting and may make a typo
here though so it would all need to be tested.  I probably should turn
this more into a distributable example.  But hopefully it will be
useful as it is regardless.

#!/bin/sh

# Short summary description of your program.

# Copyright 2008 Bob Proulx <bob@proulx.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Longer description here as needed.
#
# Examples:
#
#   progname arg1
#   progname --verbose arg1 arg2

progname=$(basename $0)
version=@VERSION@

print_usage()
{
    # This script is designed to use help2man to build the man page
    # directly from the script itself.
    #   help2man programname
    # Check the man page formatting after making changes here.
    cat <<'EOF'
Description of script goes here.

This is both your man page when run through help2man and your online
help.  Document your program here.

Usage: programname [options]

Options:
 -v, --verbose      verbose operation
 -n, --dry-run      not really, just print what would be done
     --help         print this help message
     --version      print program version

Examples:

  $ programname --help

  $ programname --verbose --dry-run

  $ programname arg1 arg2

Report bugs to <bug-address@example.com>.
EOF
}

print_version()
{
    echo "$progname $version"
    echo "Copyright (C) 2008 Your Name <you@example.com>."
    echo "License GPLv3+: GNU GPL version 3 or later"
    echo "<http://gnu.org/licenses/gpl.html>"
    echo "This is free software: you are free to change and redistribute it."
    echo "There is NO WARRANTY, to the extent permitted by law."
    echo ""
    echo "Written by Your Name <you@example.com>."
}

SHORTOPTS="dmnv"
LONGOPTS="daily,monthly,help,verbose,version"

if $(getopt -T >/dev/null 2>&1) ; [ $? = 4 ] ; then # New longopts getopt.
    OPTS=$(getopt -o $SHORTOPTS --long $LONGOPTS -n "$progname" -- "$@")
else # Old classic getopt.
    # Special handling for --help and --version on old getopt.
    case $1 in --help) print_usage ; exit 0 ;; esac
    case $1 in --version) print_version ; exit 0 ;; esac
    OPTS=$(getopt $SHORTOPTS "$@")
fi

if [ $? -ne 0 ]; then
    echo "'$progname --help' for more information" 1>&2
    exit 1
fi

eval set -- "$OPTS"

daily=false
monthly=false
verbose=false
while [ $# -gt 0 ]; do
    : debug: $1
    case $1 in
        -d|--daily)
            daily=true
            shift
            ;;
        -m|--monthly)
            monthly=true
            shift
            ;;
        --help)
            print_usage
            exit 0
            ;;
        -n|--dry-run)
            notreally=true
            shift
            ;;
        --quiet)
            quiet=true
            shift
            ;;
        -v|--verbose)
            verbose=true
            shift
            ;;
        --version)
            print_version
            exit 0
            ;;
        --)
            shift
            break
            ;;
        *)
            echo "Internal Error: option processing error: $1" 1>&2
            exit 1
            ;;
    esac
done

if $daily && $monthly; then
   echo "Error: Both daily (-d) and monthly (-m) were specified." 1>&2
   exit 1
fi

if ! $daily && ! $monthly; then
   echo "Error: Neither daily (-d) nor monthly (-m) were specified." 1>&2
   exit 1
fi

$verbose && echo "Processing..."

if $daily; then
   echo "Doing daily stuff..."
fi

if $monthly; then
   echo "Doing monthly stuff..."
fi

exit 0

Hope this helps,
Bob




reply via email to

[Prev in Thread] Current Thread [Next in Thread]