Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Are there some built-in tools that will recognize -x and --xxxx as switches, and not arguments, or do you have to go through all the input variables, test for dashes, and then parse the arguments thereafter?

share|improve this question
add comment

4 Answers

up vote 10 down vote accepted

Use getopts.

It is fairly portable as it is in the POSIX spec. Unfortunately it doesn't support long options. There is an interesting approach that does some preprocessing on the argument list to translate long options into short ones that getopts recognizes.

See also this getopts tutorial courtesy of the bash-hackers wiki and this question from stackoverflow.

If you only need short options, typical usage pattern for getopts (using non-silent error reporting) is:

# process arguments "$1", "$2", ... (i.e. "$@")
while getopts "ab:" opt; do
    case $opt in
    a) aflag=true ;; # Handle -a
    b) barg=$OPTARG ;; # Handle -b argument
    \?) ;; # Handle error: unknown option or missing required argument.
    esac
done
share|improve this answer
2  
It should be mentioned that getopt should always be verified as GNU getopt before you use it, but you shouldn't use it anyway as getopts is more portable (and generally nicer) anyway. If you do need to call it for some reason, call it in a GNU-specific way, and ensure that GETOPT_COMPATIBLE is not in the environment. –  Chris Down Sep 18 '11 at 20:38
add comment

I assume you're using bash or similar. An example:

all=false
long=false

while getopts ":hal" option; do
  case $option in
    h) echo "usage: $0 [-h] [-a] [-l] file ..."; exit ;;
    a) all=true ;;
    l) long=true ;;
    ?) echo "error: option -$OPTARG is not implemented"; exit ;;
  esac
done

# remove the options from the positional parameters
shift $(( OPTIND - 1 ))

ls_opts=()
$all && ls_opts+=( -a )
$long && ls_opts+=( -l )

# now, do it
ls "${ls_opts[@]}" "$@"
share|improve this answer
1  
+1 for using += with an array. Didn't know you could do that. Nice! –  James Sneeringer Oct 14 '11 at 21:31
add comment

You have to write a cycle to parse the parameters. Indeed you can use getopts command to do it easily.

This is a simple example from getopts manual page:

aflag=
bflag=
while getopts ab: name
do
    case $name in
    a)    aflag=1;;
    b)    bflag=1
          bval="$OPTARG";;
    ?)    printf "Usage: %s: [-a] [-b value] args\n" $0
          exit 2;;
    esac
done
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"
share|improve this answer
add comment

I wrote a script recently for work that was versatile and allowed for multiple kinds of switches in any order. I can't disclose the full script for obvious legal reasons (not to mention I don't have it with me at the moment), but here's the meat of it.. you can put it in a subroutine and call it at the end of your script:

options () {

    if [ -n "$1" ]; then # test if any arguments passed - $1 will always exist
        while (( "$#" )); do  # process ALL arguments
            if [ "$1" = ^-t$ ]; then # -t short for "test"
                # do something here THEN shift the argument
                # shift removes it from $@ and reduces $# by
                # one if you supply no argument
                shift

            # we can also process multiple arguments at once
            elif [[ "$1" =~ ^--test=[:alnum:]{1,8}$ ]] && [[ "$2" =~ ^-t2$ ]] && [[ -n "$3" ]]; then # check for 3 arguments
                # do something more then remove them ALL from the arg list    
                shift 3
            else
                echo "No matching arguments!"
                echo "Usage: [script options list here]"
            fi
        done
    else
        echo "Usage: [script options list here]"
        exit 0
    fi
}

options "$@" # run options and loop through/process ALL arguments

I do recommend limiting your bash script to less than 400 lines/15k characters; my aforementioned script grew past this size and became greatly difficult to work on. I started rewriting it in Perl, which is much better suited for the task. Keep that in mind as you work on your scripts in bash. Bash is great for small scripts and oneliners, but anything more complex and you're better off writing it in Perl.

Note, I haven't test the above, so it probably doesn't work, but you get the general idea from it.

share|improve this answer
    
The way you call options at the end is not correct, it will return -bash: syntax error near unexpected token $@. Call it as options "$@". –  Chris Down Sep 18 '11 at 22:46
    
Yup, I mixed up Perl and Bash. Corrected. –  laebshade Sep 19 '11 at 2:32
    
That while condition should not be (($#)) instead? –  manatwork Sep 19 '11 at 7:45
    
Why would you need two sets of parentheses for $#? Edit: you're right. Fixed it to while (( "$#" )) –  laebshade Sep 20 '11 at 0:47
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.