Get mandatory arguments for getopts - bash

I want to make some flags and their corresponding arguments as mandatory in getopts. The way I am doing so is by checking if the argument was passed or not for the mandatory flag, like so (flag for -i and it's argument should be mandatory):
In test.sh:
while getopts "i:n:d:r:p:s:l:" opt; do
case $opt in
i) thefile=$OPTARG;;
n) size=$OPTARG;;
d) dmax=$OPTARG;;
r) rmsd=$OPTARG;;
p) penalty=$OPTARG;;
s) sampling=$OPTARG;;
l) log=$OPTARG;;
h) printf "Usage: `basename $0` options -i [input_file.txt]\n \
-i input file\n \
-n size\n \
-d dist\n \
-r rflag\n \
-p pflag \n \
-l 0/1 for generating log file (optional, default=1)\n \
-h for help \n";;
\? ) echo "Unknown option: -$OPTARG" >&2; exit 1;;
: ) echo "Missing option argument for -$OPTARG" >&2; exit 1;;
* ) echo "Unimplemented option: -$OPTARG" >&2; exit 1;;
esac
done
if [ "s" == "s$thefile" ]
then
echo "-i must be included with a specified file" >&2
exit 1
fi
The problem is that one can run the script as so:
./test.sh -i -n 4 and it still runs with the value of -i as "-n". How can I make this foolproof, so the flag is always used and used with a valid string argument for it?

Related

Bash getopts doesn't show error for second option

I want a script to take in two options, both are required. if I pass one in, the script doesn't print an error requesting you to pass in a second one.
-bash-4.2$ bash test.sh -b
Invalid option: b requires an argument
-bash-4.2$ bash test.sh -p
Invalid option: p requires an argument
-bash-4.2$ bash test.sh -b sdfsfd
-bash-4.2$ bash test.sh -p sdfsfd
-bash-4.2$ bash test.sh -b sdfsfd -s sfd
Invalid option: s
Code
showHelp()
{
cat << EOF
Find files in client's folder and upload to S3 bucket.
Usage: $(basename $0) [-p PATH_TO_SEARCH] [-b S3 bucket]
OPTIONS:
-h Show this help message
-p Path to search
-b S3 Bucket
EOF
exit 1
}
while getopts ":p:b:h" o; do
case "${o}" in
h)
showHelp
;;
p)
p=${OPTARG}
;;
b)
b=${OPTARG}
;;
\? )
echo "Invalid option: $OPTARG";;
: )
echo "Invalid option: ${OPTARG} requires an argument";;
esac
done
shift $((OPTIND-1))
if [ -z "${p}" ]; then
showHelp
fi
if [ -z "${b}" ]; then
showHelp
fi
If you want to ensure you get both options, you can use something like:
no_p=1
no_b=1
while getopts ":p:b:h" o; do
case "${o}" in
h)
showHelp
;;
p)
p=${OPTARG}
no_p=0
;;
b)
b=${OPTARG}
no_b=0
;;
\? )
echo "Invalid option: $OPTARG";;
: )
echo "Invalid option: ${OPTARG} requires an argument";;
esac
done
[[ $no_p -eq 1 ]] && echo "No -p provided" && exit 1
[[ $no_b -eq 1 ]] && echo "No -b provided" && exit 1

How to make an argument optional in getopts bash?

I would like to make one of the optional characters (-t) which should not accept any argument in getopts bash. This is where i got so far
while getopts ":hb:q:o:v:t" opt; do
case $opt in
b)
Blasting_list=$OPTARG
;;
l)
query_lincRNA=$OPTARG
;;
q)
query_species=$OPTARG
;;
o)
output=$OPTARG # Output file
;;
t)
species_tree=$OPTARG
;;
h)
usage
exit 1
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
I want to run the above script like this..
bash test.sh -b Blasting_list.txt -l Sample_query.fasta -q Atha -o test_out -v 1e-20 -t
Then it should execute the below loop
(-----)
if [ ! -z $species_tree ];
then
mkdir -p ../RAxML_families
perl /Batch_RAxML.pl aligned_list.txt
rm aligned_list.txt
else
rm aligned_list.txt
fi
(-----)
And if i run like this, it should skip the loop.
bash test.sh -b Blasting_list.txt -l Sample_query.fasta -q Atha -o test_out -v 1e-20
(-----)
(-----)
I tried to play with getopts options but i cannot make it work.
probably the easiest way is to set species_tree to true iff there's the -t command line flag:
species_tree=false # <-- addition here
while getopts ":hb:q:o:v:t" opt; do
case $opt in
...
t)
species_tree=true # <-- change here
;;
...
esac
done
if $species_tree; then # <-- change here
...

How to pass in shell scripts mandatory and optional flags in command line using getopts?

I want to pass 3 parameters with getopts to my shell script. The script requires at least the first 2, the third parameter is optional. If it is not set, its default is used. So that the following would both work:
sh script.sh -a "/home/dir" -b 3
sh script.sh -a "/home/dir" -b 3 -c "String"
I tried to do it like the following, but it constantly ignores my entered parameters.
usage() {
echo "Usage: Script -a <homedir> -b <threads> -c <string>"
echo "options:"
echo "-h show brief help"
1>&2; exit 1;
}
string="bla"
while getopts h?d:t:a: args; do
case $args in
-h|\?)
usage;
exit;;
-a ) homedir=d;;
-b ) threads=${OPTARG};;
-c ) string=${OPTARG}
((string=="bla" || string=="blubb")) || usage;;
: )
echo "Missing option argument for -$OPTARG" >&2; exit 1;;
* )
echo "Unimplemented option: -$OPTARG" >&2; exit 1;;
esac
done
I'm new to this getopts, before I just added the parameters in a specific order, which I don't want to do here. I have read a lot questions in here, but unfortenatly didn't find it the way I need it.
I really would appriciate your help here. Thanks:)
You have several mistakes in your script. Most importantly, $args only contains the letter of the option, without the leading dash. Also the option string you gave to getopts (h?d:t:a:) doesn't fit to the options you actually handle (h, ?, a, b, c). Here is a corrected version of the loop:
while getopts "h?c:b:a:" args; do
case $args in
h|\?)
usage;
exit;;
a ) homedir=d;;
b ) threads=${OPTARG};;
c ) string=${OPTARG}
echo "Entered string: $string"
[[ $string=="bla" || $string=="blubb" ]] && usage;;
: )
echo "Missing option argument for -$OPTARG" >&2; exit 1;;
* )
echo "Unimplemented option: -$OPTARG" >&2; exit 1;;
esac
done

Bash getopts does not recognize parameter

while getopts ":hufc:p:i" opt; do
case $opt in
h)
usage
exit 1
;;
u)
DOUPDATE=false
;;
f)
DOCONFIRMATION=false
;;
c)
CUSTOMERTYPE=$OPTARG
;;
p)
CUSTOMERPROFILE=$OPTARG
;;
i)
echo "LOL $INSTALL"
INSTALL=true
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
Above is my bash code. When I try to use "i" as a parameter in the command line, case i is not entered.
What should I do?
If your command line has any invalid options prior to the i, it won't parse any farther than the error. If your command line has a -c or -p without a subsequent argument to go into CustomerType or CustomerProfile, it will not parse any farther.
#Examples that should work
script.sh -i
script.sh -c customerX -p profileX -i
script.sh -iz
#Examples that will not work
script.sh -hi #-h option will exit before it parses -i
script.sh -zi #invalid option z will exit
script.sh -c customerX -p -i #Missing required argument after -p

bash getopts with multiple and mandatory options

Is it possible to use getopts to process multiple options together? For example, myscript -iR or myscript -irv.
Also, I have a situation where based on a condition script would need mandatory option. For example, if argument to script is a directory, I will need to specify -R or -r option along with any other options (myscript -iR mydir or myscript -ir mydir or myscript -i -r mydir or myscript -i -R mydir), in case of file only -i is sufficient (myscript -i myfile).
I tried to search but didn't get any answers.
You can concatenate the options you provide and getopts will separate them. In your case statement you will handle each option individually.
You can set a flag when options are seen and check to make sure mandatory "options" (!) are present after the getopts loop has completed.
Here is an example:
#!/bin/bash
rflag=false
small_r=false
big_r=false
usage () { echo "How to use"; }
options=':ij:rRvhm'
while getopts $options option
do
case "$option" in
i ) i_func;;
j ) j_arg=$OPTARG;;
r ) rflag=true; small_r=true;;
R ) rflag=true; big_r=true;;
v ) v_func; other_func;;
h ) usage; exit;;
\? ) echo "Unknown option: -$OPTARG" >&2; exit 1;;
: ) echo "Missing option argument for -$OPTARG" >&2; exit 1;;
* ) echo "Unimplemented option: -$option" >&2; exit 1;;
esac
done
if ((OPTIND == 1))
then
echo "No options specified"
fi
shift $((OPTIND - 1))
if (($# == 0))
then
echo "No positional arguments specified"
fi
if ! $rflag && [[ -d $1 ]]
then
echo "-r or -R must be included when a directory is specified" >&2
exit 1
fi
This represents a complete reference implementation of a getopts function, but is only a sketch of a larger script.

Resources