ederlf
ederlf

Reputation: 261

How to create a bash script with optional parameters for a flag

I'm trying to create a script which will have a flag with optional options. With getopts it's possible to specify a mandatory argument (using a colon) after the flag, but I want to keep it optional.

It will be something like this:

./install.sh -a 3

or

./install.sh -a3

where 'a' is the flag and '3' is the optional parameter that follows a.

Thanks in advance.

Upvotes: 9

Views: 28066

Answers (5)

Alepac
Alepac

Reputation: 1831

My solution:

#!/bin/bash
count=0
skip=0
flag="no flag"
list=($@) #put args in array
for arg in $@ ; do #iterate over array
    count=$(($count+1)) #update counter
    if [ $skip -eq 1 ]; then #check if we have to skip this args
        skip=0
        continue
    fi
    opt=${arg:0:2} #get only first 2 chars as option
    if [ $opt == "-a" ]; then #check if option equals "-a"
       if [ $opt == $arg ] ; then #check if this is only the option or has a flag
            if [ ${list[$count]:0:1} != "-" ]; then #check if next arg is an option
                skip=1 #skip next arg
                flag=${list[$count]} #use next arg as flag
            fi
       else
            flag=${arg:2} #use chars after "-a" as flag
       fi 
    fi
done

echo $flag

Upvotes: -1

Dipto
Dipto

Reputation: 2738

The following is without getopt and it takes an optional argument with the -a flag:

for WORD; do
        case $WORD in
            -a?)  echo "single arg Option"
                SEP=${WORD:2:1}
                echo $SEP
                shift ;;
            -a) echo "split arg Option"
                if [[ ${2:0:1} != "-" && ${2:0:1} != ""]] ; then
                 SEP=$2
                 shift 2
                 echo "arg present"
                 echo $SEP
                else
                 echo "optional arg omitted"
                fi ;;
            -a*) echo "arg Option"
                SEP=${WORD:2}
                echo $SEP
                shift ;;
            -*) echo "Unrecognized Short Option"
                echo "Unrecognized argument"
            ;;
        esac
done

Other options/flags also can be added easily.

Upvotes: 2

chepner
chepner

Reputation: 530940

The getopt external program allows options to have a single optional argument by adding a double-colon to the option name.

# Based on a longer example in getopt-parse.bash, included with
# getopt
TEMP=$(getopt -o a:: -- "$@")
eval set -- "$TEMP"
while true ; do
   case "$1" in
     -a)
        case "$2" in 
          "") echo "Option a, no argument"; shift 2 ;;
          *) echo "Option a, argument $2"; shift 2;;
        esac ;;
     --) shift; break ;;
     *) echo "Internal error!"; exit 1 ;;
   esac
done

Upvotes: 9

Xavier S.
Xavier S.

Reputation: 1157

In bash there is some implicit variable:

    $#: contains number of arguments for a called script/function

    $0: contains names of script/function
    $1: contains first argument
    $2: contains second argument
    ...
    $n: contains n-th argument

For example:

    #!/bin/ksh

    if [ $# -ne 2 ]
    then
        echo "Wrong number of argument - expected 2 : $#"
    else
        echo "Argument list:"
        echo "\t$0"
        echo "\t$1"
        echo "\t$2"
    fi

Upvotes: -1

Randy Howard
Randy Howard

Reputation: 2156

Use the getopt feature. On most systems, man getopt will yield documentation for it, and even examples of using it in a script. From the man page on my system:

The following code fragment shows how one might process the arguments for a command that can take the options -a and -b, and the option -o, which requires an argument.

       args=`getopt abo: $*`
       # you should not use `getopt abo: "$@"` since that would parse
       # the arguments differently from what the set command below does.
       if [ $? != 0 ]
       then
               echo 'Usage: ...'
               exit 2
       fi
       set -- $args
       # You cannot use the set command with a backquoted getopt directly,
       # since the exit code from getopt would be shadowed by those of set,
       # which is zero by definition.
       for i
       do
               case "$i"
               in
                       -a|-b)
                               echo flag $i set; sflags="${i#-}$sflags";
                               shift;;
                       -o)
                               echo oarg is "'"$2"'"; oarg="$2"; shift;
                               shift;;
                       --)
                               shift; break;;
               esac
       done
       echo single-char flags: "'"$sflags"'"
       echo oarg is "'"$oarg"'"

This code will accept any of the following as equivalent:

       cmd -aoarg file file
       cmd -a -o arg file file
       cmd -oarg -a file file
       cmd -a -oarg -- file file

Upvotes: -1

Related Questions