im currently updating my first script i wrote to print room schedules
I want to use getopts to parse my options now my question:
My Options are to print the schdule for all rooms are:
-w for the next day
-e to print the schedule for monday on friday
-c current day
-O with an given offset
So far so good.
No i want to print only one room with following options:
-rw
-re
-rc
-rO
How can i manage that with getopts? Something like that?
while getopts :a:b:c:d:hP: ARG; do
case $ARG in
ab) #set option "a"
echo "-a used: $OPTARG"
echo "OPT_A = $OPT_A"
;;
cd) #set option "b"
echo "-b used: $OPTARG"
echo "OPT_B = $OPT_B"
;;
Is that possible? I hope you understand what i mean...
You can simply define a variable ONE_ROOM which is set to true if the option r is given. You don't need to manually distinguish between all possible combinations of your arguments.
#!/bin/bash
ONE_ROOM="0"
while getopts rwecO: ARG; do
case $ARG in
r) ONE_ROOM="1";;
w) ;;
e) ;;
c) ;;
O) ;;
esac
done
if [ "$ONE_ROOM" -eq "1" ] ; then
# print only one room
else
# print all rooms
fi
Related
I am trying to extend the getopts from the sourced script as below.
if an option other than a,b,c,d is passed in, it needs to print "invalid option" and exit.
script_a.sh:
#!/bin/bash
script_a_getopts() {
while getopts 'a:b:' OPT; do
case "$OPT" in
a)
a=$OPTARG
;;
b)
b=$OPTARG
;;
*)
echo "invalid option"
exit 1
;;
esac
done
}
script_b.sh
#!/bin/bash
source script_a.sh
while getopts ':c:d:' OPT; do
case "$OPT" in
c)
c=$OPTARG
;;
d)
d=$OPTARG
;;
[?])
script_a_getopts $#
esac
done
echo "a=$a"
echo "b=$b"
echo "c=$c"
echo "d=$d"
When I run the script, it don't work as expected, obviously I am making a mistake.
$ ./script_b.sh -c cat -d dog -a apple -b boy
a=
b=
c=cat
d=dog
Didn't throw error when -x is passed.
$ ./script_b.sh -x
a=
b=
c=
d=
Short Answer: You have to rollback the OPTIND before calling script_a_getopts.
case "$OPT" in
c)
c=$OPTARG
;;
...
[?])
let OPTIND--
script_a_getopts $#
esac
done
Long Answer:
The getopts track which arguments have been processed using the OPTIND variable. When the top getopts recognized unknown item, it has already 'consumed' it by moving OPTIND to the next argument. To get script_a_getopts to process that argument, the OPTIND need to be rolled back to point to the unprocessed argument.
The let OPTIND-- will allow the unrecognized argument to be re-processed.
Side note, if you want to allow options to be placed in arbitrary order (-c cat -a apple -d dog -b boy) you will have to repeat the same in the script_a_getopts. This will require improved error processing in script_a_getopts function.
Background
In bash I have a working getopts interface as depicted below:
while getopts "a:b:c:d:" OPTION ; do
case "$OPTION" in
a) JET="$OPTARG" ;;
b) FUEL="$OPTARG" ;;
c) CAN="$OPTARG" ;;
d) MELT="$OPTARG" ;;
*) echo "Usage $0 -a A -b B -c C -d D"; exit 1 ;;
esac
done
shift $((OPTIND-1))
#Check out input parameters
for PARAM in JET FUEL CAN MELT; do
echo "$PARAM in [${!PARAM}]"
done
Question
What is the cshell translation for this? I cannot find a clear example of getopts (with an s) in cshell, yet there is an easily findable one for bash. This is distinct from attempting to use getopt, since getopts is an entirely different function from getopt.
I have 8 options which are mandatory to run the script. However I am unable to pass option values after the first argument. Could you please let me know what I am doing wrong here.
#!/usr/bin/env bash
usage() { echo "Usage: $0 -f sample_R1.fastq -r sample_R2.fastq -hrp HISAT2_REFERENCE_PATH -g GTF_file -sp KNOWN_SPLICE_FILE -b BOWTIE2_REFERENCE.fasta -rsem_path RSEM_REFERENCE -out_path OUTPUT_PATH -h help" 1>&2; exit 1; }
while getopts ":f:r:hrp:g:s:b:rsem_path:out_path:h" opt; do
case "${opt}" in
f) f="$OPTARG"; shift ;; # sample_R1.fastq
r) r="$OPTARG"; shift ;; # sample_R2_fastq
hrp) hrp="$OPTARG"; shift ;; # HISAT2_REFERENCE_PATH
g) g="$OPTARG"; shift ;; # GTF_file
sp) sp="$OPTARG"; shift ;; # KNOWN_SPLICE_FILE
b) b="$OPTARG"; shift ;; # BOWTIE2_REFERENCE
rsem_path) rsem_path="$OPTARG"; shift ;; #RSEM Reference path
out_path) out_path="$OPTARG"; shift ;; #Results output path
h | *) usage ; exit;;
esac
done
echo "f = ${f}"
echo "r = ${r}"
echo "hrp = ${hrp}"
echo "g = ${g}"
echo "sp = ${sp}"
echo "b = ${b}"
echo "rsem_path = ${rsem_path}"
echo "out_path = ${out_path}"
Results
f = ./test_data/HBR_Rep1_ERCC-Mix2_Build37-ErccTranscripts-chr22.read1.fastq
r =
hrp =
g =
sp =
b =
rsem_path =
out_path =
There are a number of problems here:
getopts only does single-letter options, and will treat -hrp as a shorthand for -h -r -p (just like ls -la is short for ls -l -a). There is a semi-standard format for long options (that start with a double dash, e.g. ls --color), but getopts doesn't support this.
getopts sets the option variable (opt in this case) to the option not including the -, so your cases should look like e.g. f) instead of -f).
Don't use shift in the middle of the getopts loop. getopts keeps track of where it is in the argument list, and if the argument list gets shifted while it's working on it... things get very confused. Instead, use shift $((OPTIND-1)) after the loop to get rid of all of the options that've been dealt with.
You're not actually capturing the option values. That is, when parsing -f sample_R1.fastq, getopts will set OPTARG to "sample_R1.fastq" but you ignore that and just set f to the string "true".
And finally, you started the option string with ":", which tells getopts it shouldn't report errors because you'll take are of that, but you don't. Also, even without that ":", if getopts sees an option that isn't on the list, it'll run the loop with opt set to "?", so you should check for that and give the usage message in that case.
Here's my take at a corrected version:
#!/usr/bin/env bash
usage() { echo "Usage: $0 -f sample_R1.fastq -r sample_R2.fastq -H HISAT2_REFERENCE_PATH -g GTF_file -s KNOWN_SPLICE_FILE -b BOWTIE2_REFERENCE.fasta -R RSEM_REFERENCE -o OUTPUT_PATH [-h]" 1>&2; exit 1; }
while getopts "f:r:H:g:s:b:R:o:h" opt; do
case "${opt}" in
f) f="$OPTARG" ;; # sample_R1.fastq
r) r="$OPTARG" ;; # sample_R2_fastq
H) hrp="$OPTARG" ;; # HISAT2_REFERENCE_PATH
g) g="$OPTARG" ;; # GTF_file
s) sp="$OPTARG" ;; # KNOWN_SPLICE_FILE
b) b="$OPTARG" ;; # BOWTIE2_REFERENCE
R) rsem_path="$OPTARG" ;; #RSEM Reference path
o) out_path="$OPTARG" ;; #Results output path
h | [?]) usage ; exit;;
esac
done
shift $((OPTIND-1))
echo "f = ${f}"
echo "r = ${r}"
echo "hrp = ${hrp}"
echo "g = ${g}"
echo "sp = ${sp}"
echo "b = ${b}"
echo "rsem_path = ${rsem_path}"
echo "out_path = ${out_path}"
Note that if you want to give an error message if some options were omitted, you need to check that all of those variables got set. Something like if [ -z "$f" ] || [ -z "$r" ] ||...
You don't need the "-" in the case statement and so -f should f -r r etc.
I am working on a shell script that allows users to set options.
The script is working fine if the user specifies options seperately. For instance:
./my_file.sh -r -l directory1 directory2
The command above is working perfectly, however my script doesn't work if the user specifies the following command:
EDIT: What I mean is that the -l option is not recognized if the user enters the command below
./my_file.sh -rl directory1 directory2
This is the code I am using to read the options
while getopts 'lvibrd:v' flag; do
case "${flag}" in
l) option_l=true
shift ;;
v) option_v=true
shift ;;
i) option_i=true
shift ;;
b) option_b=true
shift ;;
r) option_r=true
shift ;;
d) option_d=true
shift ;;
*) echo "Invalid options ${flag}"
exit 1 ;;
esac
done
Is there a way to read options with multiple letters, such as -rl, using similar code?
Thank you in advance.
Try the following (simplified):
while getopts 'lr' flag; do
case "$flag" in
l) echo "option -l was set";;
r) echo "option -r was set";;
*) echo "Invalid options ${flag}"
exit 1 ;;
esac
done
shift $(($OPTIND - 1))
echo "$#"
Omitted shift makes the difference. The shifting confuses getopts builtin.
This works correctly for both single and combined options:
$ ./nic.sh -rl hello world
option -r was set
option -l was set
hello world
EDIT: I've added code to print the rest of arguments (after those processed by getopts).
I'm quite new to ubuntu and bash scripting and wanted to know why I might be getting this error when using GETOPTS.
here is the code I use to run it.
sh /home/ubuntu/Desktop/test.sh -f /home/u/Desktop/ -p 'TEST'
I think i'm calling the script correctly, and it should search for the term I enter as a search term using grap. but for some reason it doesn't. Any advice on what I can do as a general rule when working with grep would also be appreciated, thanks.
#!/bin/bash
valid=0
file_arg=""
display_help=""
column=""
pattern=""
while getopts f:d:s:m: opt
do
case "$opt" in
d) display_help=$OPTARG
;;
f) file_arg=$OPTARG
;;
c) column=$OPTARG
;;
p) pattern=$OPTARG
;;
*) valid=1
break
;;
esac
done
if [ $valid -eq "0" ]
then
if [ $pattern != "" ]
then
cat $file_arg | grep $pattern
else
cat $file
fi
else
echo -n "Usage: FILE -f <name> | COLUMN -> -c <name> | HELP -> -d | PATTERN -> -p <expression>"
fi
In getopts you not specify p option you only have f:d:s:m: options.
I think you mean p instead m or vice versa.
It should f:d:s:m:p: or f:d:s:p:
You should also consider the error supression and error handling features of getopts.
If the very first character of the option string is a colon (:) then getopts will not report errors and instead will provide a means of handling the errors yourself. Two additional characters can then be used within your case conditional handling:
? If an invalid option is entered then $opt will be set to ? and $OPTARG will hold the invalid character, e.g. if -z was used, which is not in your option string, then $OPTARG will be set to z.
: If a required additional argument is omitted by the user then $opt will be set to : and $OPTARG will hold the command character, e.g. if -p was used instead of -p arg then $OPTARG will be set to p.
If this is implemented then the catch-all of * becomes redundant and should be removed. Note: If you leave it in and it is above either ? or : then you'll be asking for problems. Also make sure the ? is escaped like this \?).
Hope this helps.
# Note the addition of the inital colon before 'f'.
while getopts :f:d:c:p: opt;
do
case $opt in
d) display_help=$OPTARG
;;
f) file_arg=$OPTARG
;;
c) column=$OPTARG
;;
p) pattern=$OPTARG
;;
# Option error handling.
\?) valid=0
echo "An invalid option has been entered: $OPTARG"
;;
:) valid=0
echo "The additional argument for option $OPTARG was omitted."
;;
# This is now redundant:
# *) valid=0
# break
# ;;
esac
done
There are a couple of other issues with your script, as Jayesh mentioned, you need to include all parameters for getopt but you also need to be careful with string comparisons, here's a couple more fixes with suggestions:
(See http://www.tldp.org/LDP/abs/html/comparison-ops.html for string comparison info)
#!/bin/bash
# switch around valid, convention is 1 == true and 0 == false
valid=1
file_arg=""
display_help=""
column=""
pattern=""
# getopt patterns need to match following case statement
while getopts f:d:c:p: opt;
do
case $opt in
d) display_help=$OPTARG
;;
f) file_arg=$OPTARG
;;
c) column=$OPTARG
;;
p) pattern=$OPTARG
;;
*) valid=0
break
;;
esac
done
# changed value to reflect true false convention
if [ "$valid" -eq "1" ]
then
# string comparison in bash should be done using specific operators
if [ -n "$pattern" ]
then
cat $file_arg | grep $pattern
else
# typo, this should be file_arg?
cat $file_arg
fi
else
echo -n "Usage: FILE -f <name> | COLUMN -> -c <name> | HELP -> -d | PATTERN -> -p <expression>"
fi