order parameters in getopts - linux

I have to write very simple script. It should take 2 args -h and -q. Both are optional, -h can be somewhere. So, -h -q should does the same action like -q -h. If I pass -a ,or -a -a -a - an error should occurs (I mean exit 1). If I pass -a -h -a -a -b.... - it should return "I couldn't recognize -a" + invoke help case. So -h has priority.
Could you help me?
while getopts "hq" OPTION
do
case $OPTION in
h)
echo "Help here!" ;
exit 0;
esac
done
shift $(($OPTIND - 1))
while getopts "hq" OPTION
do
case $OPTION in
q) #quiet - return 0, do nothing.
exit 0;;
*) #If -a or sth
echo "I couldn't recognize args"
echo "Help here"
exit 1
;;
esac
done

This is the correct implementation:
#!/usr/bin/env bash
while getopts :hq OPTION
do
case $OPTION in
h) echo "Help here!" ;
exit 0;;
q) echo "quiet do nothing."
exit 0;;
?) echo "I couldn't recognize option [$1]"
exit 1;;
esac
done
shift $((OPTIND - 1))
Note :hq and ?) to process incorrect options (-a -b ...)

Related

getopts with all optional arguments

In order to run a bash script I need some arguments and flags, since the requirements are pretty tricky I've chosen to use a getopt function like this
while getopts ":s:g:r" o; do
case "${o}" in
s)
# Variables that require value
VALUE1=${OPTARG}
;;
g)
# Variables that require value
MGROUP=${OPTARG}
;;
r)
# Variables that, if present, set just a flag
ASROOT=1
;;
*)
echo "Usage: ./myscript.sh -s value1 -g value2 -r"
;;
esac
done
I would like to have all parameters optional so I can write some conditions later in my code, and first two (s and g) with an arguments, the third (r) is only a optional flag. In the future I may need to add additional parametrers, always optional.
Any advice?
Sample script illustrating optional arguments with bash getopts in a style similar to mysql client. "--" is also supported.
Usage:
script.sh [-u ] [-p | -p] [--] arg1 arg2 ...
#!/bin/bash
#
# Sample script illustrating optional arguments with bash getopts in
# a style similar to mysql client. "--" is also supported.
#
# tgage#nobigfoot.com - 5-Oct-2019 - Distribute/use without restriction.
#
# Defaults
username="$(whoami)"
unset password
while getopts ":u:p:" arg; do
case $arg in
u) # Username
username="$OPTARG"
;;
p) # Password
thisarg=$((OPTIND - 1)); thisarg="${!thisarg}"; thisarg="${thisarg:2}"
if [[ ! -z $OPTARG ]] && [[ "$OPTARG" != "$thisarg" ]]; then
unset password
OPTIND=$((OPTIND - 1))
else
password="$thisarg"
fi
if [[ -z $password ]]; then
read -s -p "Password: " password
echo
fi
;;
\?)
# Request Help
echo "Sorry that I can be of no help."
;;
*)
# Deal with option at end of line
OPTION=$((OPTIND - 1)); OPTION="${!OPTION}"
case $OPTION in
--)
# Add support for --
break
;;
-p)
# Option with optional argument
unset password
read -s -p "Password: " password
echo
;;
*)
# Invalid argument
echo "Error; Invalid option \"$OPT\"." >&2
;;
esac
;;
esac
done
shift $((OPTIND -1))
echo "Username: $username"
echo "Password: $password"
echo
echo "Remaining arguments:$*"
echo
The optional parameter are optional to make mandatory check VALUE1 and MGROUP. For example:
[[ -n $VALUE1 && -n $MGROUP ]] || {
echo "mandatory paramter missing"
exit 1
}
getopts

getopts is not sending my options to standard out

I'm beginning to experiment with getopts but am running into a few errors. When I enter an invalid option such as -A the program output is not what it needs to be.
#!/bin/bash
function usage() {
echo "Usage: $0 -h [database host] -d [test database name]"
exit 1
}
while getopts “:h:d:” opt; do
case ${opt} in
h)
db_host=$OPTARG
;;
d)
test_db=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" 1>&2
usage
exit 1
;;
:)
echo “Option -$OPTARG requires an argument.” 1>$2
usage
exit 1
;;
esac
done
shift $((OPTIND-1))
if [ -z $db_host ] || [ -z $test_db ]; then
usage
else
echo "Your host is $db_host and your test database is $test_db."
fi
Example program output:
./opt.sh: illegal option -- A
Invalid option: -
Usage: ./opt.sh -h [database host] -d [test database name]
So, basically two questions:
1) I want to get rid of this first error message altogether. I want to provide my own error messages.
2) Why isn't my script producing "Invalid option: -A" instead of just "Invalid option: -"
You have the wrong types of quotes around the options argument to getopts, they're "curly quotes" instead of ASCII double quotes. As a result, : wasn't the first character of the options, so you weren't getting silent error reporting.
Change it to
while getopts ':h:d:' opt; do

not allow multiple option in getopts of bash script

Having bash script as follows
#! /bin/bash
usage()
{
echo -e "need help!"
}
while getopts ":a:b:h" OPTION
do
case $OPTION in
a)
printf "a option with value %s\n" $OPTARG
;;
b)
printf "b option with value %s\n" $OPTARG
;;
h)
usage
;;
?)
echo -e "No option selected"
;;
esac
done
exit 0
Above script run fine with different option but i wanted to extend it to not allow to pass multiple option at same time like as following argument
$ ./test.bash -a 1 -b 2
a option with value 1
b option with value 2
should be not valid means some way it give me error like wrong syntax i achieved it by as follows but it seems to long it is as follow
#! /bin/bash
usage()
{
echo -e "need help!"
}
let "a_count=0"
let "b_count=0"
MY_ARG=""
while getopts ":a:b:h" OPTION
do
case $OPTION in
a)
let a_count=1
MY_ARG=$OPTARG
;;
b)
let b_count=1
MY_ARG=$OPTARG
;;
h)
usage
;;
?)
echo -e "No option selected"
;;
esac
done
[[ $a_count -eq 1 ]] && [[ $b_count -eq 1 ]] && echo "wrong command sytax" && exit 0
[[ $a_count -eq 1 ]] && printf "a option with value %s\n" $MY_ARG
[[ $b_count -eq 1 ]] && printf "b option with value %s\n" $MY_ARG
exit 0
run like
$ ./test.bash -a 1 -b 2
wrong command sytax
But i want to finish validation in while..loop of getopts. Also this validation not works for following command
./test.bash -a -b
a option with value -b
any one have batter idea how to use getopts for this type validation?
you've almost got it. The : after the a and after the b say that they take an argument, so your example with -a -b is actually valid, saying "There is option a with value -b".
If you really just want "-a or -b and then an argument", you probably don't need getopts at all, but should do:
[ "$1" == "-a" ] && printf "a option with value %s\n" $2
[ "$1" == "-b" ] && printf "b option with value %s\n" $2
any one have batter idea how to use getopts for this type validation?
well, actually, you're explicitly telling geptopts that -a and -b are not boolean parameters, but parameters that take an extra argument. The argument parser cannot tell whether the argument following -a is a parameter or its own argument, and thus they consider [-a ] [-b ] as syntax.
The best way, would actually be to have a different boolean parameter that matches the use case when you do not want an argument for -a and -b.
Though, it won't help you with your issue trying to have parameters with argument or boolean, but for the argument syntax checking you can try docopt which has a nicer way to create command line interface. You focus on doing the --help documentation, it parses it to build your parameter/argument parser. e.g.:
eval "$(docopts -V - -h - : "$#" <<EOF
Usage: myscript [(-a <foo> | -b <bar> | -abool | -bbool)]
-a <foo> The A option.
-b <bar> The B option.
-abool The A bool
-bbool The B bool
--help Show help options.
--version Print program version.
----
myscript 0.0.0
Copyright (C)20.. Your Name
License...
)"
if $a ; then
echo "a option! with $a"
fi
if $b ; then
echo "b option! with $b"
fi
if $abool ; then
echo "abool option!"
fi
if $bbool ; then
echo "bbool option!"
fi
This is not quite perfect because it will always process the first switch, but it does place an exit inside the while loop which is in keeping with your design requirement. It may give you an idea how to finish it.
#!/bin/bash
usage()
{
echo -e "need help!"
}
while getopts "a:b:h" OPTION
do
case $OPTION in
a)
aflag=1
aval=$OPTARG
if [ ! -z "$bflag" ]
then
printf "ERROR: cant use both -a and -b\n"
exit 1
fi
;;
b)
bflag=1
bval=$OPTARG
if [ ! -z "$aflag" ]
then
printf "ERROR: cant use both -a and -b\n"
exit 1
fi
;;
h) usage ;;
?) printf "ERROR" ; exit 1 ;;
esac
done
if [ ! -z "$aflag" ]
then
printf "a option with value %s $aval\n"
elif [ ! -z "$bflag" ]
then
printf "b option with value %s $bval\n"
fi
exit 0
If you still want to use the getopts I would use bash built-in variable for the arguments count $# to detect wrong number of arguments passed:
#! /bin/bash
usage()
{
echo -e "need help!"
}
# Check if number of arguments is greater than 2 as "-a1" (one arg) and "-a 2" are correct.
# You might want to check for other wrong inputs.
if [ $# > 2 ]
then
echo "Some warning t o the user or"
usage
exit 1
fi
while getopts ":a:b:h" OPTION
do
case $OPTION in
a)
printf "a option with value %s\n" $OPTARG
;;
b)
printf "b option with value %s\n" $OPTARG
;;
h)
usage
;;
?)
echo -e "No option selected"
;;
esac
done
exit 0

Bash multiple combinations in getopts

I would like to make a script where you can give a couple of parameters with it:
while getopts ":a:b:c:" opt; do
case $opt in
a)
echo "-a was triggered
;;
b)
echo "-b was triggered
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
The code I have now works but the problem I have is that I want to give another function/echo if it combines.
Example:
When I do: .MyScript -ab than it should give another function that what is defined in "a" or in "b"
so a bit like:
ab) -> Script -a -b or Script -ab
echo "-ab was triggered"
What is the best solution to do this?
Any ideas, your free to post!
while getopts ":a:b:c:" opt; do
case $opt in
a)
echo "-a was triggered"
a_val=$OPTARG
;;
b)
echo "-b was triggered"
b_val=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
if [[ -n $a_val ]]; then do something with "$a_val"; fi
if [[ -n $b_val ]]; then do something with "$b_val"; fi
The only situation this may cause confusion is if the user passes -a "" -- one workaround is:
a=false
b=false
while getopts ":a:b:c:" opt; do
case $opt in
a) echo "-a was triggered"; a_val=$OPTARG; a=true ;;
b) echo "-b was triggered"; b_val=$OPTARG; b=true ;;
esac
done
if $a; then do something with "$a_val"; fi
if $b; then do something with "$b_val"; fi
Here, there are no brackets: if $a; then ... because I'm invoking the command "true" or "false" and acting on that exit status.
UPDATED
You can use the getopt(1) linux utility. This is not a bash internal function, but this can handle long arguments.
Try this:
declare -A OPTARG
GetOpt() {
local prog="${BASH_SOURCE[0]}"
[ $# -eq 0 ] && echo "$prog: Bad call of GetOpts">&2 && exit 1
local longopt="$1"
shift
local tmp
tmp=$(getopt -n"$prog" -a -l "$longopt" -- '' "$#") || exit
eval "tmp=($tmp)"
local i
for((i=0;i<${#tmp[*]};++i)){
key=${tmp[i]#--}
[ -z "$key" ] && break
if [[ "${tmp[i+1]}" =~ ^-- ]]; then OPTARG[$key]=1
else OPTARG[$key]="${tmp[++i]}"
fi
}
for((j=0;++i<${#tmp[*]};++j)){ OPTFILE[j]=${tmp[i]};}
}
GetOpt "a b ab file:" "$#"
[ "${OPTARG[a]}" -a "${OPTARG[b]}" ] && OPTARG[ab]=1 && unset OPTARG[a] OPTARG[b]
[ "${OPTARG[a]}" ] && echo Do a
[ "${OPTARG[b]}" ] && echo Do b
[ "${OPTARG[ab]}" ] && echo Do ab
The defined GetOpt function will place the parsed command line argument with the checked long options to the associative array called OPTARG. If there is an error it will fail informing about the problem.
With getopt's -a option you can use -ab or --ab format. Keep in mind that if You have del defined, then the -d option (if -d is not specified) will expand to --del.
If You specify an arg with additional option it can contain spaces. E.g. if -l file: defined in getopt then it can be used as ./test --file="q w". ${OPTARG[file]} will be q w.
The OPTFILE array contains the optional arguments (args given after --).

shell script with arguments presented

#!/bin/bash
#if present -a flag then print this echo
#echo "A";
#if -b is present then print b
#echo "B"
#and if -c 10 present how can I read this value '10' ?
above is how I want to look my script
and I want to be able to start it like this
myscript.sh -a -b -c 10
or
myscript.sh
or
myscript.sh -a -c 10
or
myscript.sh -c 10
and so on
Type 'man getopt' at your shell, and follow the instructions.
Use getopts like this:
arg=-1
while getopts "c:ab" optionName; do
case "$optionName" in
a) echo "-a is present";;
b) echo "-b is present";;
c) arg="$OPTARG"; echo "-c is present [$arg]";;
esac
done
You may have a look at getopts .
The following example is taken from http://wiki.bash-hackers.org/howto/getopts_tutorial
#!/bin/bash
while getopts ":a" opt; do
case $opt in
a)
echo "-a was triggered!" >&2
;;
\?)
echo "Invalid option: -$OPTARG" >&2
;;
esac
done
#!/bin/bash
for var in "$#"
do
echo "$var"
http://osr600doc.sco.com/en/SHL_automate/_Passing_to_shell_script.html

Resources