LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Blogs > Nominal Animal
User Name
Password

Notices


Rate this Entry

Pure Bash option handling

Posted 04-16-2012 at 01:44 AM by Nominal Animal

I like the standard getopt way of specifying script and/or program parameters, but I don't like its quirks, and it is pretty cryptic if you don't use it often enough.

Here is pure Bash skeleton to implement script option parsing. It is long, but it should be easier to read and understand than one implemented using getopt.
Code:
#!/bin/bash
set +f                  # Enable filename globbing
set -B                  # Enable brace expansion
shopt -s dotglob        # Include names that start with a dot
shopt -s nullglob       # No match expands to an empty string


# Create a safe temporary directory to put temporary files into,
# and make sure it is automatically deleted after this script exits.
# You can use any filename "$WORK/filename" as a temporary file.
# Omit this if you dont need it.
WORK="$(mktemp -d)" || exit $?
trap "rm -rf '$WORK'" EXIT


# Output usage to standard error, then exit.
# Exit status is optional (default 0), first parameter.
#
Usage () {
    exec >&2

    echo ""
    echo "Usage: $0 [-h|--help]"
    echo "       $0 [-t TYPE|--type=TYPE] FILES..."
    echo ""

    exit $[ $1-0 ]
}


# TYPE is stored in this parameter.
# You can also set a default value.
unset Type

# If you want no parameters to yield the usage,
# uncomment the next line:
# [ $# -gt 0 ] || Usage 0

# Parse command line arguments.
#
args=()
while [ $# -gt 0 ]; do

    # No options follow --
    if [ "$1" = "--" ]; then
        shift 1
        args=("${args[@]}" "$@")
        shift $#
        continue
    fi

    # Not an option?
    if [ "${1:0:1}" != "-" ]; then
        args[${#args[@]}]="$1"
        shift 1
        continue
    fi

    # A long option?
    if [ "${1:0:2}" == "--" ]; then

        # Skip the two dashes at start, and consume this one
        option="${1:2}"
        shift 1

        # --option=value or --option value
        value="${option#*=}"
        if [ "$value" = "$option" ]; then
            value="$1"
            valueshift=1
        else
            option="${option%%=*}"
            valueshift=0
        fi
        #
        # If $value is used, then do
        #   shift $valueshift

        # Long options:
        #
        case "$option" in

          help)
            Usage 0
            ;;

          type)
            Type="$value"
            shift $valueshift
            ;;

          *)
            echo "--$option: Unknown option." >&2
            exit 1
            ;;

        esac

    elif [ "$1" = "-" ]; then

        # A single dash is interpreted as "standard input".
        shift 1
        args[${#args[@]}]="/dev/stdin"

    else

        # Short option or multiple short options. Consume.
        options="${1:1}"
        shift 1

        # Handle each short option character separately.
        while [ ${#options} -gt 0 ]; do

            # Short options are handled character-by-character.
            option="${options:0:1}"
            options="${options:1}"

            # Short options:
            #
            case "$option" in

              h)
                Usage 0
                ;;

              t)
                Type="$1"
                shift 1
                ;;

              *)
                echo "-$option: Unknown option." >&2
                exit 1
                ;;

            esac
        done

    fi
done
# Set positional arguments "back".
set -- "${args[@]}"


#
# The actual script starts here.
#

if [ $# -gt 0 ]; then
    printf '%d command line parameters:\n' $#
    printf '\t\047%s\047\n' "$@"
else
    printf 'No command line parameters.\n'
fi

if test -v Type ; then
    printf 'TYPE was specified as \047%s\047.\n' "$Type"
else
    printf 'TYPE was not specified.\n'
fi
The way this skeleton works is that the huge loop parses all command line parameters, handles both short and long options (-p or -p value or --parameter or --parameter=value or --parameter value), and finally puts back all non-option parameters into the positional parameters list ($1, $2,...).

Option processing stops at -- so that users can supply files beginning with a dash easier.

Parameter - is converted automatically to positional parameter /dev/stdin, i.e. the standard input "file". This way users can specify - to refer to standard input.

Unknown options will abort the script. Currently, the skeleton supports only the standard options -h and --help to output the usage, and an example option -t TYPE or --type=TYPE or --type TYPE .

Run the skeleton to see how it behaves. Any comments or questions are welcome.
Posted in Uncategorized
Views 2541 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 11:32 PM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration