Reputation: 1193
I'm trying to create a shell script that has two mandatory arguments (arg1, arg2) and then an optional -b flag plus the argument that needs to follow should the user choose to use the flag.
Let me explain:
It's an install script that takes an advantage of GIT to fetch an application from a Github repository. The user types in terminal f.ex.:
./shellscript.sh new <app_name> # fetches master branch by default
and the script fetches an instance of the master branch from this repository. Should the user however choose to use the optional -b flag that would mean that he/she wants to specify which branch to fetch, e.g. develop branch. Meaning that the user could do:
./shellscript.sh new <app_name> -b develop # or which ever branch there is available
I'm also curious how you could go about making the script work so that it wouldn't matter if the user types in the -b flag+branch_name before the 'new' argument and the 'app_name' argument. But that is perhaps not the most important thing at the moment.
To know what exactly I'm trying to build, here is a link to my current script that only takes the two mandatory arguments and only fetches the master branch: My Super Cool Artisan Executable Script
P.S.: I've been trying out many examples using getopts which I've found both here on Stackoverflow and other blogs out there but none have helped me to completely make it work. Thus am I here asking y'all great people for help.
Huge thanks and be sure to check out my Linux Mint / Ubuntu - Post Install Script for only cool people(you guys and those switching over to Linux from Windows/Mac)
Regards, Villi
Upvotes: 2
Views: 11216
Reputation: 7610
A little bit simplified version, using that getopts
can report errors:
#!/usr/bin/bash
help() { echo -e "Usage\n\t$0: new <app_name> [-b <develop>]" >&2;}
die() { [ -n "$1" ] && echo -e "Error: $1\n" >&2; help; [ -z "$1" ]; exit;}
[ $# -lt 2 ] && die "Too few args"
[ $1 != "new" ] && die "Bad first arg ($1)"
app_name=$2
shift 2
unset develop
while getopts "b:" opt; do
case $opt in
\?) exit 1;;
b) develop="$OPTARG";;
esac
done
echo "app_name: $app_name, develop: $develop"
Test:
$./test new App
app_name: App, develop:
$./test new App -b Dev
app_name: App, develop: Dev
Anyway I may suggest to use to use the standard way of argument passing. Instead of new
you may use -n
.
Upvotes: 1
Reputation: 241671
Unix utilities normally take optional arguments ("flags") before the positional arguments, although most GNU utilities, including the GNU implementation of the C library function getopt
, shuffle command line arguments so that the optional arguments come first. However, the bash builtin getopts
does not shuffle, which means that it is up to you to do so if you want to.
getopts
always starts with the argument whose number is the value of the variable OPTIND
. (OPTIND is set to 1 every time a bash function is executed, and it's a global variable. So a bit of caution is needed with bash functions which call each other.) If you want to, you can set OPTIND yourself, and the next call to getopts
will start with that index. Alternatively, you can use shift
to shift all the command line arguments over.
So, for example, you could do this:
# "shift" version: always shift consumed arguments
local verb="$1" branch=master app_name option
shift
case $verb in
new) app_name="$1"
shift
while getopts b: option; do
case $option in
b) branch=$OPTARG;;
*) # handle the error;;
esac
done
shift $((OPTIND - 1));;
*) # handle the error or other subcommands;;
esac
# At this point, there are still arguments if ((OPTIND > 0))
Or:
# non-shift version: use OPTIND to index arguments
local verb="${!OPTIND}" branch=master app_name option
OPTIND=$((OPTIND + 1))
case $verb in
new) app_name="${!OPTIND}"
OPTIND=$((OPTIND + 1))
while getopts b: option; do
case $option in
b) branch=$OPTARG;;
*) # handle the error;;
esac
done;;
*) # handle the error or other subcommands;;
esac
# At this point, there are still arguments if ((OPTIND > $#))
Upvotes: 2
Reputation: 8819
I normally write my own to allow for short and long options:
function Usage()
{
cat <<-ENDOFMESSAGE
$0 [OPTION] REQ1 REQ2
options:
-b -branch branch to use
-h --help display this message
ENDOFMESSAGE
exit 1
}
function Die()
{
echo "$*"
exit 1
}
function GetOpts() {
branch=""
argv=()
while [ $# -gt 0 ]
do
opt=$1
shift
case ${opt} in
-b|--branch)
if [ $# -eq 0 -o "${1:0:1}" = "-" ]; then
Die "The ${opt} option requires an argument."
fi
branch="$1"
shift
;;
-h|--help)
Usage;;
*)
if [ "${opt:0:1}" = "-" ]; then
Die "${opt}: unknown option."
fi
argv+=(${opt});;
esac
done
}
GetOpts $*
echo "branch ${branch}"
echo "argv ${argv[@]}"
Upvotes: 7