Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BASH using both positional and optional arguments in a script

Tags:

bash

sh

I am currently writing a BASH script in which I would like to use both positional and optional arguments. The positional arguments must occur at the location specified (ex: $1, $2) while the optional arguments can occur at any position denoted by their command line flag. Here is my script:

#!/usr/bin/env bash

usage() {
cat << EOF
Usage: progam ACTION NAME -k KEY_NAME
    ACTION ...... The program action to initiate
    NAME ........ The name of the object to create
    KEY_NAME .... The key name to use
EOF
}

ACTION=$1
NAME=$2
KEY_NAME=""

while getopts "k:" opt; do
    case $opt in
        k) KEY_NAME=$OPTARG; ;;
        [?]) usage && exit 1;
    esac
done

if [[ ! $ACTION ]]; then
    echo "Please select an action."
    exit 1
fi

if [[ ! $NAME ]]; then
    echo "Please include a name for the object."
    exit 1
fi

if [[ "$KEY_NAME" != "" ]]; then
    python3 -m program $ACTION -k $KEY_NAME -n $NAME
else
    echo "Please include a key name."
    exit 1
fi

exit 0

to run the program I would expect to be able to do the following:

fun_bash [action] [name] -k [key_name]

Where the things in brackets would be replaced by actual strings. When I execute, I always hit the condition that the key name does not exist:

Please include a key name.

How can I include mandatory positional arguments and optional command line flags within the same script?

like image 891
d_kennetz Avatar asked Aug 09 '26 18:08

d_kennetz


1 Answers

You may be be able to use a work-around in your current script as:

#!/usr/bin/env bash    
usage() {
cat << EOF
Usage: progam ACTION NAME -k KEY_NAME
    ACTION ...... The program action to initiate
    NAME ........ The name of the object to create
    KEY_NAME .... The key name to use
EOF
}

action="$1"
name="$2"
shift 2

key_name=""    
while getopts "k:" opt || :; do
    case $opt in
        k) key_name=$OPTARG; break ;;
        [?]) shift;;
    esac
done    
if [[ -z $action ]]; then
    echo "Please select an action."
    exit 1
fi    
if [[ -z $name ]]; then
    echo "Please include a name for the object."
    exit 1
fi    
if [[ -n $key_name ]]; then
    python3 -m program $action -k $key_name -n $name
else
    echo "Please include a key name."
    exit 1
fi    

Key difference is use of shift 2 before while loop that shifts argument by 2 positions since your first 2 arguments are fixed.

Also note use of [?]) shift;; inside getopts loop which shifts an argument every time it doesn't meet known options i.e. -k.

Also note that you should avoid using all uppercase variable names in your script to avoid overriding a builtin shell variable.

With these changes all the following command lines are accepted:

fun_bash arg1 arg2 -k mykey
fun_bash arg1 arg2 arg3 arg4 -k mykey
fun_bash arg1 arg2 arg3 arg4 arg5 -k mykey
like image 199
anubhava Avatar answered Aug 12 '26 18:08

anubhava



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!