getopts when first option is a path in bash - bash

I'm having an issue with getopts in a bash script. Basically my script would have to be called with something like:
./myScript /path/to/a/folder -a -b
What I have at the top of my code is this:
while getopts ":ab" opt; do
case $opt in
a)
variable=a
;;
b)
variable=b
;;
\?)
echo "invalid option -$OPTARG"
exit 0
esac
done
echo "$variable was chosen"
Now, this works as long as I call my script without /path/to/a/folder… How can I make it to work with it instead?
Thanks a lot

If you MUST put a path before the arguments, use a shift command to pop the first positional argument off, and leave the rest for getopts.
# Call as ./myScript /path/to/a/folder -a -b
path_argument="$1"
shift # Shifts away one argument by default
while getopts ":ab" opt; do
case $opt in
a)
variable=a
;;
b)
variable=b
;;
\?)
echo "invalid option -$OPTARG"
exit 0
esac
done
echo "$variable was chosen, path argument was $path_argument"
The more-standard answer, as Etan mentioned, is to put the non-option arguments AFTER the options. Prefer this style, as it makes your script more consistent with built-in POSIX option parsing.
# Call as ./myScript -a -b /path/to/a/folder
while getopts ":ab" opt; do
case $opt in
a)
variable=a
;;
b)
variable=b
;;
\?)
echo "invalid option -$OPTARG"
exit 0
esac
done
shift $((OPTIND - 1)) # shifts away every option argument,
# leaving your path as $1, and every
# positional argument as $#
path_argument="$1"
echo "$variable was chosen, path argument was $path_argument"

Related

How can I pass options to another script in bash only if they have been set?

I have two bash scripts, do-foo-for-thing.sh and do-foo-for-many-things.sh.
do-foo-for-thing.sh takes a number of arguments, parsed using getopts, most of which are optional and have default values defined in the script.
I would like do-for-for-many-things.sh to call do-for-for-thing.sh with any of these options that have been provided, but not to use any options that have not been provided (so that they are not required for the -many-things script, and they single-thing scripts owns the default values).
I've tried to look up ways to do this, but had no luck - I'm not super familiar with bash. I can easily pass in all arguments, but that doesn't work if I don't want to provide all the potential options to the -many-things script.
Rough examples below;
do-foo-for-thing.sh
A=default-A
B=default-B
C=default-C
if [ $# -ge 1 ]; then
OPTIND=1
while getopts "a:b:c:p:" opt; do
case "$opt" in
a) A=$OPTARG ;;
B) B=$OPTARG ;;
C) C=$OPTARG ;;
P) P=$OPTARG ;;
\?) echo "Unrecognized option: -$OPTARG" >&2; exit 1 ;;
esac
done
shift $((OPTIND-1))
fi
do-foo-that-uses-values-A-B-and-C-on-P
do-foo-for-many-things.sh
if [ $# -ge 1 ]; then
OPTIND=1
while getopts "d:a:b:c:" opt; do
case "$opt" in
d) D=$OPTARG ;;
a) A=$OPTARG ;;
B) B=$OPTARG ;;
C) C=$OPTARG ;;
\?) echo "Unrecognized option: -$OPTARG" >&2; exit 1 ;;
esac
done
shift $((OPTIND-1))
fi
for P in `ls D`
do
./do-for-for-thing.sh -p P
done
This currently only passes P in. I'd like to pass in A, B, and C as well - but only if they've been provided to this script (so that any that have not been use the default values in do-foo-for-thing).
So remember the arguments and pass them along. Use bash array to properly accumulate properly quoted arguments. Use http://shellcheck.net to check your scripts.
args=()
OPTIND=1
while getopts "d:a:b:c:" opt; do
case "$opt" in
d|a|B|C) args+=(-"$opt" "$OPTARG"); ;;
\?) echo "Unrecognized option: -$OPTARG" >&2; exit 1 ;;
esac
done
shift $((OPTIND-1))
find D -maxdepth 1 -mindepth 1 -exec ./do-for-for-thing.sh "${args[#]}" -P {} "$#" \;
You have a few options here:
1. Pass through
You could simply pass the arguments through using the $# bash variable that represents all command line arguments.
./do-for-for-thing.sh -p P "$#"
2. Build argument string
Instead of:
case "$opt" in
d) D=$OPTARG ;;
a) A=$OPTARG ;;
B) B=$OPTARG ;;
C) C=$OPTARG ;;
Do
argstr=()
case "$opt" in
d) D=$OPTARG; argstr+=("-d $D ") ;;
a) A=$OPTARG; argstr+=("-a $A ") ;;
B) B=$OPTARG; argstr+=("-b $B ") ;;
C) C=$OPTARG; argstr+=("-c $C ") ;;
And then:
./do-for-for-thing.sh -p P ${argstr[#]}

Bash script not getting input variable

I have a simple bash script, see below
#!/bin/bash
while getopts "t" opt; do
case $OPT in
t) JWT_TOKEN="$OPTARG"
;;
\?) echo "Invalid option -$OPTARG" >&2
;;
esac
done
echo "Token value is $JWT_TOKEN"
A simple test call is
my-script.sh -t 'test'
However this creates the following output
sedavidw#MacbookPro~$ sh my-script.sh -t 'test'
Token value is
sedavidw#MacbookPro~$
UPDATE
Was able to fix my script by changing it to
#!/bin/bash
while getopts "t:" opt; do
case "${opt}" in
t) JWT_TOKEN="$OPTARG"
;;
\?) echo "Invalid option -$OPTARG" >&2
;;
esac
done
echo "Token value is $JWT_TOKEN"
From the comments it looks like the t: change was helpful for the argument. But still not clear on the syntax change for the "${opt}" part, and would like some clarity there

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
...

Shell script getopts optarg no value

Could someone examine this code snippet and tell me why when I call this script with a -p abcdef that $OPTARG never has the passed in argument value?
# Process command-line options passed as switches to this script
while getopts "ph:" option; do
case "$option" in
p)
{
if [ -n "$OPTARG" ]; then
echo
echo "##### SCRIPT ERROR: You failed to provide a host prefix. #####"
echo
usage
break
else
echo "Setting host prefix to '$OPTARG'"
echo
HOST_PREFIX=$OPTARG
fi
} ;;
h) usage ;;
'?') usage ;;
*) break ;;
esac
done
shift "$((OPTIND-1))" # Shift off the options and optional --.
All options that requires arguments must be succeeded by :, it should be written as p:h as h option doesn't required arguments.

Avoid options to be taken as argument automatically

I'd like to do some error checking for a bash script I am writing. In particular, I wish to ensure the following option not to be considered as the argument of an option (intentionally) left empty.
Let's say the following snippet
while getopts “hhelpc1:2:” OPTION
do
case "$OPTION" in
h|help)
usage
exit 1
;;
1)
var1=${OPTARG}
;;
2)
var2=${OPTARG}
;;
c)
test1
;;
esac
done
Assuming my script is called test.sh
By doing something like
./test.sh -1 -2 dddd -c
In the above circumstance test1 output an error message that -2 option is empty. On the opposite, I'd like to raise a warning for -1 being empty, whereas at present -2 will be taken as the argument for -1.
Any help?
Thanks
Andrea
getopts:
only handles short option names, so you cannot put "help" in your option string -- that means you're looking for "-h", "-e", "-l", "-p"
cannot look for missing arguments the way you're hoping. You'll have to examine $OPTARG to check if it looks like one of your options.
Add a leading : to the opt string to handle getopts errors yourself.
Here's a reworking of your code and I'm sure there are plenty of cases I'm not catching
#!/bin/bash
usage () { echo usage ...; }
test1 () { echo test1; }
shopt -s extglob
while getopts ":hc1:2:" opt
do
case $opt in
h)
usage
exit 1
;;
1)
case $OPTARG in
-[hc2]*)
echo "error: required argument missing for -1"
usage
exit 1
;;
*) var1=$OPTARG
;;
esac
;;
2)
case $OPTARG in
-[hc1]*)
echo "error: required argument missing for -2"
usage
exit 1
;;
*) var2=$OPTARG
;;
esac
;;
c)
test1
;;
:)
echo "error: required argument missing for -$OPTARG"
usage
exit 1
;;
\?)
# unknown argument, handle accordingly
;;
esac
done
shift $((OPTIND - 1))
echo "var1=$var1"
echo "var2=$var2"
echo "rest=$*"
Update 2014-01-23
Here's one technique:
do_test1=false
while getopts ...
case $opt in
...
c) do_test1=true ;;
...
esac
done
shift $((OPTIND - 1))
# execute function "test1" if "-c" was given:
$do_test1 && test1

Resources