bash getopts options for different functions - bash

how can I make this work? I want to use different functions for my command, my problem is how can I pass arguments to the add.sh function? find.sh works fine but the first two commands says no arg for -v / -a option. What am I doing wrong?
while getopts v:a:s opt
do
case "$opt" in
v) ./view.sh;;
a) ./add.sh;;
s) ./find.sh;;

If you want to pass the -v option onto the view.sh script, then do so:
while getopts v:a:s opt
do
case "$opt" in
v) ./view.sh -v "$OPTARG";;
a) ./add.sh -a "$OPTARG";;
s) ./find.sh;;
esac
done
If you want to pass the 'other' arguments to view.sh too, then you have to work a bit harder. You could simply pass all the arguments with ./view.sh "$#";; but being selective is harder.

Related

Issue with getops parameter

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.

Using getopts with a switchless path

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.

How to use getopts with unix shell functions?

The getopts command doesn't seem to work in a function. Maybe I did something wrong. The code below is what I have now. it is working if I put the whole while loop outside function. I am wondering if there is a way to make getopts work with functions ? I am new to the shell script. Any help would be appreciated :)
getOptions()
{
while getopts :al:f:vd opt; do
case "$opt" in
l) logFile = $OPTARG ;;
f) fileTable = $OPTARG ;;
v) verbose = 1 ;;
d) set -x ;;
a) echo "a";;
\?) echo "Invalid option: -$opt";;
esac
done
shift $(($OPTIND - 1))
}
One reason might be your usage of things like logFile = $OPTARG when you shouldn't have any spaces there (it should read logFile=$OPTARG).
Another reason is the fact that $1, $2, etc. are all referring to the function's arguments, not the shell script's arguments. Since the shell works that way, and getopts uses $1, $2, etc., you're using the function's arguments with getopts, not the script's arguments. In other words, confining your option processing to a shell function is not a good idea.

Parsing a flag with a list of values

I'm creating a bash script which involves parsing arguments. The usage would be:
$ ./my_script.sh -a ARG_1 -b ARG_2 [-c LIST_OF_ARGS...]
Using getopts I'm able to parse -a and -b and get their respective values ARG_1 and ARG_2. If and only if user places -c as last argument, then I'm also able to get -c and create a list with all values in LIST_OF_ARGS....
But I would not like to force user to insert -c as the last flag. For instance, it would be great if the script can be invoked this way:
$ ./my_script.sh -b ARG_2 -c V1 V2 V3 -a ARG_1
Here is my current code:
while getopts a:b:c opt
do
case $opt in
a)
A_FLAG=$OPTARG
;;
b)
B_FLAG=$OPTARG
;;
c)
# Handle values as regular expressions
args=("$#")
C_LIST=()
for (( i=$OPTIND-1 ; i <= $#-1 ; i++ ))
do
C_LIST=("${C_LIST[#]}" ${args[$i]})
done
;;
?)
usage
;;
esac
done
You need to separate your detection of the -c flag with the processing associated with it. For example, something like:
while getopts a:b:c opt
do
case $opt in
a)
A_FLAG=$OPTARG
;;
b)
B_FLAG=$OPTARG
;;
c)
C_FLAG=1
;;
?)
usage
;;
esac
done
# discard all of our options.
shift `expr $OPTIND - 1`
if [ "$C_FLAG" = 1 ]; then
# Handle values as regular expressions
args=("$#")
C_LIST=()
for (( i=0 ; i <= $#-1 ; i++ ))
do
C_LIST=("${C_LIST[#]}" ${args[$i]})
done
fi
This script doesn't collect all the non-option arguments until after processing all the command line options.
Here's a question: why have a -c option at all?
If the full usage involves a list of values, why not just have no -c option and allow the -a and -b options only while the rest are regular args as in ./myscript.sh -a ARG_1 -b ARG_2 [argument ...], where any arguments are optional (like the -c option and its arguments are in your usage example?
Then your question becomes "how do I intersperse program options and arguments", to which I would respond: "You shouldn't do this, but to achieve this anyway, parse the command line yourself; getopts won't work the way you want it to otherwise."
Of course, parsing is the hard way. Another possibility involves adding the values after -c to a list, so long as you don't encounter another option or the end of the options:
C_LIST=()
while getopts a:b:c: opt; do
#Skipping code...
c)
C_LIST+="$OPTARG"
shift $(expr $OPTIND - 1)
while [ -n "$1" ] && [ $(printf "%s" "$1" | grep -- '^[^-]') ]; do
C_LIST+="$1"
shift
done
OPTIND=1
;;
The behaviour of getopts is mimicked: even if OPTARG begins with a '-' character, it is still kept, but after OPTARG, any string starting with the '-' character may simply be an invalid option such as -n. I used printf instead of echo because some versions of echo, such as the one that bash has built-in, have a -e option that may or may not allow the loop to continue, which isn't desired. The grep expression should prevent this, but who knows if that version of echo allows for -e'hello', which would cause grep to succeed because it sees "hello"? While possibly unnecessary, why take chances?
Personally, I'd avoid this behaviour if you can, but I also don't understand why you're asking for this behaviour in the first place. If I were to recommend anything, I'd suggest the more common /path/to/script -a ARG_1 -b ARG_2 [argument ...] style above any other possible choice of implementation.
On my system, I haven a /usr/share/doc/util-linux/examples/getopt-parse.bash file. It puts the result of getopt into a variable, and set the positional parameters to that variable. Then uses a switch similar to yours, but uses shift to remove arguments when found.
You could do something similar, but for your -c option use shift until you get an option or run out of arguments.
Or it might be enough for you to use your current solution, but remember to set the OPTIND variable after the loop.

How to have a positional argument before options in a shell script?

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

Resources