8

In below code when I give option r then getopts requires one arguments:

while getopts ":hr::l:" opt; do
    case $opt in
        r ) echo "Run Numbers - argument = $OPTARG " ;;
        l ) echo "Latency range - argument = $OPTARG" ;;
        h ) helptext
            graceful_exit ;;
        * ) usage
            clean_up
            exit 1
    esac
done

But I need to pass two arguments after -r option, instead of one. Is there an easy way to do this?

16

You cannot pass two arguments with single option using getopts.

I recommend the following alternatives:

  1. Put quotes around multiple arguments

    In this case getopts will treat them as one argument, but you will be able to split it later on. You can even put all arguments in the array at once:

    #!/bin/bash  
    
    while getopts ":hr:l:" opt; do
        case $opt in
            r ) echo "Run Numbers - argument = $OPTARG "
                set -f # disable glob
                IFS=' ' # split on space characters
                array=($OPTARG) ;; # use the split+glob operator
            l ) echo "Latency range - argument = $OPTARG" ;;
            h ) helptext
                graceful_exit ;;
            * ) usage
                clean_up
                exit 1
        esac
    done
    
    echo "Number of arguments: ${#array[@]}"
    echo -n "Arguments are:"
    for i in "${array[@]}"; do
      echo -n " ${i},"
    done
    printf "\b \n"
    

    The example of run:

    ./script -r "123 456 789"
    

    And output:

    Run Numbers - argument = 123 456 789 
    Number of arguments: 3
    Arguments are: 123, 456, 789
    
  2. Use comma (or other preferred character) as a delimiter

    ./script -r 123,456,789
    

    and you just replace IFS=" " with IFS=, in the code above. That one has the advantage of allowing empty elements. As pointed out in the comments section this solution is chosen by some common programs e.g. lsblk -o NAME,FSTYPE,SIZE.

  3. Allow multiple -r options

    Multiple -r, but each taking only one argument:

    ./script -r 123 -r 456 -r 789
    

    Then arguments would be added to array one by one

    array+=("$OPTARG")
    

    That one has the advantage of not having limitations on what characters the elements may contain. This one is also used by some standard linux tools e.g. awk -v var1=x -v var2=y.

  • 3
    The comma delimiter idea is good, as it's used by various standard commands, notably mount. – PM 2Ring Oct 26 '14 at 3:06
  • Possible, one can still transform this "delimited" form into array with array=(${OPTARG//,/ }). Yet another possibility is to just use multiple times -r arg option each time adding element to an array array+=($OPTARG). – jimmij Oct 26 '14 at 3:29
  • Even easier: IFS=',' array=($OPTARG) – PM 2Ring Oct 26 '14 at 3:38
  • Examples: pgrep uses comma: ps -s 123,456 ..., grep uses repeating the option: grep -e pattern1 -e pattern2 ... (-e is optional when only one pattern is used). – Volker Siegel Oct 26 '14 at 6:34
  • 2
    you don't want to make the user do more work e.g. put quotes around the list, just because of a limitation in the language/library you are using. However the use of , seems reasonable, even preferable to the use of a space. – ctrl-alt-delor Oct 26 '14 at 8:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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