Take the 2-minute tour ×

What would the best approach be to parse argument value ranges using getopts? As an example:

$ script.sh -r2-4,6,8-10

In my script I would then have an array with the values 2, 3, 4, 6, 8, 9 and 10.

share|improve this question
I have no experience with getopts, but if you're using Bash, why not expand the range before, e.g. {2..4}? –  slhck Dec 27 '12 at 10:17
Never thought of that, it works very well. One issue is that I have to use multiple options: -r{2..4} -r6 -r{8..10}. –  c0dem4gnetic Dec 27 '12 at 10:26
@Bhargav Bhat You linked to the wrong getopt(3), which is not the same as getopt(1). –  slhck Dec 27 '12 at 10:41
@slhck: oops! is corrected now. –  Bhargav Bhat Dec 27 '12 at 10:43
add comment

1 Answer

up vote 1 down vote accepted

If you want to both use -r...,.. and -r... -r... -r... : create a script such as this "toto.bash" :


    add_ranges () #this will add each integers or ranges (a-b) into the array: myarray
       #first we test that we only have those validchars (makes the second step below much easier to write)
       echo "$@" | grep "${validchars}" >/dev/null && {
          : ; #only valid chars, probably ok. (but could be wrong, ex: 1-  2,, 4-3  etc...)
       } || {
          echo "The ranges you entered are not valid : they should only contain such characters: ${validchars}"
          exit 1 ;
       #secondly we now try to handle the current ranges lists (comma separated)
       for range in $(echo "${@}" | tr ',' ' ')
          if   [[ ${range} =~ ^[0-9]+$ ]]     # [[ can handle regexp matching, and doesn't need to quote parameters
             myarray[${#myarray[*]}]=${range}  #add this after the latest element in myarray
          elif [[ ${range} =~ ^[0-9]+-[0-9]+$ ]]
             newrange=$(echo "$range" | sed -e 's/-/../')
             for i in `eval echo {$newrange}` # {a..b} means: all integers a to b
                myarray[${#myarray[*]}]=${i}  #add this after the latest element in myarray
             echo "ERROR: I can not recognize this range: $range"
             exit 1

   ###### handle options using getopts:
   OPTIND=1; #here for compatibility's sake: in case you add another function that uses getopts, reminds you to re-set OPTIND each time.
   while getopts "r:" zeoption; do
      case $zeoption in
            add_ranges "${OPTARG}";
        echo "option --, OPTARG=$OPTARG";
            break ;
        echo "ERROR: Unrecognized option: zeoption=$zeoption OPTARG=$OPTARG";

   shift $((OPTIND-1)) ; #we shift away all the options we processed.
   ###### end of options handling

    # and we continue here...

   echo "we now have : remaining arguments: ${@}"
   echo "and myarray contains: ${myarray[@]}"

and then run it:

$ ./toto.bash -r 2,4,6-12 -r 100-103 foo bar
we now have : remaining arguments: foo bar
and myarray contains: 2 4 6 7 8 9 10 11 12 100 101 102 103

I wanted to give just hints, but foudn out that writing it out is better. This makes for a long answer, but I hope it helps!

share|improve this answer
Brilliant! Thank you for adding comments in the script to make it easier to follow! –  c0dem4gnetic Dec 27 '12 at 13:20
you're welcome. Some parts may need comments, so if you have questions about the way I wrote this or that, please do ask. –  Olivier Dulac Dec 27 '12 at 13:28
I corrected the "elif" so that it closely match what we expect (otherwise it could contain additionnal unwanted characters before and after) –  Olivier Dulac Dec 27 '12 at 13:33
add comment

Your Answer


