Currently, I'm working on a bash script that is meant to have parameters passed through it.
My getOps lines:
while getopts ":s:d:e:*" opt; do
case $opt in
s)
kb_status
;;
d)
kb_disable
;;
e)
kb_enable
;;
*)
echo "Invalid option: -$OPTARG"
;;
esac
done
The main issue is whenever I try to pass the script through
./myscript.sh -e`
I get the following message from my wildcard parameter:
Invalid option: -e
However, when I run it as
./myscript.sh -ee
or have any second letter in the parameter, it passes perfectly fine. Can someone help me fix this issue?
The problem is the ":" character after the e in
while getopts ":s:d:e:*" opt; do
The ":" tells getopts to expect an argument after the -e option.
So if you want your script to just support -s -d and -e options, then do the following:
while getopts sde opt; do
Putting : after e in the option list means that the -e option requires an argument. -e by itself is missing the argument, -ee sets the value of the argument to e.
Since you don't do anything with $OPTARG, it looks like you don't really require arguments to your options, so you shouldn't be using : after each of them.
while getopts ":sde*" opt; do
It's also unclear why you have * at the end of the option list. That will allow "-*", but the case block will report that as an error.
Related
Trying to read my flag and their arguments,
I came accros a case where passing a flag with an expected argument,
fallowed by another flag instead of the expected argument,
would result in the second flag being interpreted as argument for the first flag.
WWW_ALIAS=0
while getopts ':d:a:w' flag; do
case "${flag}" in
d)
DOMAIN_NAME=${OPTARG}
;;
a)
IFS=',' read -ra DOMAIN_ALIASES <<< "${OPTARG}"
;;
w)
WWW_ALIAS=1
;;
:)
echo "[Error] Argument for option -${OPTARG} was omitted." 1>&2
exit 1
;;
\?)
echo "[Warning] Option ${OPTARG} is not supported and will be ignored." 1>&2
;;
esac
done
if [ -z "${DOMAIN_NAME}" ]; then
echo "[Error] Domain parameter (-d) must be set" 1>&2
exit 1
fi
Thus, running ./script.sh -w -d will trigger the error message at the end of this code example.
But running ./script.sh -d -w will instead assign -w to the DOMAIN_NAME variable while it shouldn't.
Is there a way to make sure that any flag can't be used as argument for a flag ?
The supported syntax for getopts is:
a - option -a without value; error on unsupported options
a: - option -a with value; error on unsupported options
ab - check for options -a, -b; error on unsupported options
:ab - check for options -a, -b; silences errors on unsupported options
Since you specified d:, the argument parser will check for an additional value after the switch -d. Not specifying one, just like in this command: ./script.sh -w -d will trigger an error from the argument parser (not your code).
Since you specified w without a (: after it), the argument parser will NOT check for an additional value after the switch -w. Hence you don't see an error for that flag.
When you run with -d -w, the parser sees only the first switch, which is -d, and it consumes the next token as the argument, which is the expected outcome.
As there a way to make sure that any flag can't be used as argument for a flag?
Yes, there are a couple of options actually.
Option 1: inside the menu, add a sanity check to allow only reasonable values:
...
case "${flag}" in
d)
if [[ "${OPTARG}" == -* ]]; then
echo "Bad argument!"
exit 1
fi
DOMAIN_NAME=${OPTARG}
;;
...
Option 2: Use eval set -- "$OPTS"
Some don't like this option because eval is evil. But it's still an option if you are not afraid of this attack vector.
This command will sort the arguments and will prevent things like this from happening.
Find an example here
I'm trying to use getopts inside a switch case loop.
if i use only getopts or only the switch case it's work, however when i combine those two the getopts dos not trigger.
i have search a lot but i cat fins any mention for how to combine them, and problem i missing something stupid so for give me ...
here is the code essence.
#!/bin/bash
case $1 in
ver)
echo "vesion"
exit 0
;;
op)
while getopts ":a" opt; do
case $opt in
a)
echo "-a was triggered!" >&2
;;
\?)
echo "Invalid option: -$OPTARG" >&2
;;
esac
done
;;
esac
when i do that
# bash -x test.sh op -a
i get
+ case $1 in
+ getopts :a opt
(and without debug i get nothing)
what is that that i missing to combine these two
Thanks :)
You should add a shift instruction at the beginning of your op) choice, before the call to getopts, to eat the op argument itself. Else, the first argument that getopts will analyze is op and it will silently stop (end of options).
I am trying to write a short script, utilizing getopts. I want it to take optional switches, or just run as the default. I have a -d switch to enable debugging, and I'd like every other argument to be a path. The ideal command line looks as such, with paths being optional, and theoretically limitless:
$0 [-d] [/path1[ /path2[ ...]]]
I am currently using getopts as such below:
while getopts ":d" opt; do
case $opt in
d)
DEBUG=true
;;
h)
echo USAGE: $0 \[-d\] \[\/mount\/point\/1 ...\]
exit 0
;;
\?)
echo Incorrect syntax
;;
esac
done
What can I put in the while getopts section, and in the case set, to allow paths to be entered, as many as needed?
You don't need anything in the loop or getopts call for that. getopts stops at the first non-option.
After your loop all your paths will still be in positional arguments available for use.
Also you don't have h in your getopts string so it isn't valid.
I want to have a shell script that takes a file name as first positional argument followed by options (./test.sh <file> [options]). However, getopts doesn't work when I give a positional argument before options. I have the following code:
while getopts "h" opt; do
case $opt in
h)
echo usage
;;
;;
esac
done
echo $1
./test.sh -h prints usage on the shell, but ./test.sh test -h prints test on the shell. So when I give a positional argument before an option it's not doing anything with the option. It does work when having the positional arguments after the option (change echo $1 to echo $BASH_ARGV and the call to ./test.sh -h test). How can I have the positional argument before the options?
The shell builtin getopts does not support reordering the parameters. If you want parameter reordering, you need to use one of the enhanced getopt variants (e.g. gnu getopt or bsd getopt). Please note that the default bsd getopt does not support long options (e.g. when used on Mac OS X)
Try to replace "h" to h
while getopts h opt; do...
And also you have to add minus in your case
case "$opt" in
-h)...
If you know, that your [file] will always be present, can you just use
filename="$1"
shift
And than parse other arguments
So, I'm trying my hand at using bash's built-in getopts to handle argument processing except I'm getting a strange result. Here's my test script;
#!/bin/sh
HOST=
OWNER=
GROUP=
while getopts "h:o:g" OPTION;
do
case $OPTION in
h)
HOST=$OPTARG
;;
o)
OWNER=$OPTARG
;;
g)
GROUP=$OPTARG
;;
esac
done
echo "$HOST - $OWNER:$GROUP"
Yet, when I run the script using this;
./test.sh -h test.host.com -o skittles -g whatever
My last arg never gets pulled in or is getting dropped. My result from the echo is;
test.host.com - skittles:
^ where's my group value? O.o
Does anyone know what would be causing this?
Thanks.
It seems your expect -g to have an argument, but in your options declaration, there is no ":" related to your -g.
You should have this:
h:o:g:
Your option string is missing a : after the g.