I want to make an argument as optional in getopt bash so that if the user didn't specify it, then it still runs without killing the program. How can i do that. Here is my previous code
while getopts ":l:q:s:e:hg:" opt; do
case $opt in
l)
lincRNAfasta=$OPTARG
;;
q)
query_species=$OPTARG
;;
s)
subject_species=$OPTARG
;;
e)
subject_gff=$OPTARG
;;
h)
echo "USAGE : open script in text editor"
exit 1
;;
g)
subject_genome=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
Sorry, had to update my answer, I misunderstood the question.
I was looking at the documentation for getopts.c which does support ::
But the code that you have works whether I specify 1, 2, or 3 arguments, and in any order.
If it is exiting with an error one reason could be that the variables need to be defined:
#! /bin/bash
lincRNAfasta=
query_species=
subject_species=
subject_gff=
subject_genome=
help='''
USAGE : open script in text editor
-l lincRNAfasta
-q query_species
-s subject_species
-e subject_gff
-g subject_genome
'''
while getopts ":l:q:s:e:hg:" opt; do
case $opt in
l)
lincRNAfasta=$OPTARG
;;
q)
query_species=$OPTARG
;;
s)
subject_species=$OPTARG
;;
e)
subject_gff=$OPTARG
;;
h)
printf "$help"
exit 1
;;
g)
subject_genome=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
echo "doing something else"
if [ -z "$lincRNAfasta" ];then
echo "its empty"
echo "lincRNAfasta: $lincRNAfasta"
echo
else
echo "not empty"
echo "lincRNAfasta: $lincRNAfasta"
echo
fi
if [ -z "$query_species" ];then
echo "its empty"
echo "query_species: $query_species"
echo
else
echo "not empty"
echo "query_species: $query_species"
echo
fi
if [ -z "$subject_species" ];then
echo "its empty"
echo "subject_species: $subject_species"
echo
else
echo "not empty"
echo "subject_species: $subject_species"
echo
fi
if [ -z "$subject_gff" ];then
echo "its empty"
echo "subject_gff: $subject_gff"
echo
else
echo "not empty"
echo "subject_gff: $subject_gff"
echo
fi
if [ -z "$subject_genome" ];then
echo "its empty"
echo "subject_genome: $subject_genome"
echo
else
echo "not empty"
echo "subject_genome: $subject_genome"
echo
fi
# do something once variables have been set
# any variable not set will be empty
echo "doing something else"
Output:
bob#squids:~/Desktop$ ./1.sh -h
USAGE : open script in text editor
-l lincRNAfasta
-q query_species
-s subject_species
-e subject_gff
-g subject_genome
bob#squids:~/Desktop$ ./1.sh -s a -g h -e e -q q
doing something else
its empty
lincRNAfasta:
not empty
query_species: q
not empty
subject_species: a
not empty
subject_gff: e
not empty
subject_genome: h
doing something else
bob#squids:~/Desktop$ ./1.sh -s a -g h -e e
doing something else
its empty
lincRNAfasta:
its empty
query_species:
not empty
subject_species: a
not empty
subject_gff: e
not empty
subject_genome: h
doing something else
bob#squids:~/Desktop$ ./1.sh -s a -e e -g 123
doing something else
its empty
lincRNAfasta:
its empty
query_species:
not empty
subject_species: a
not empty
subject_gff: e
not empty
subject_genome: 123
doing something else
Or instead of initializing the variables as empty, you could initialize them as a string like "NOTSPECIFIEDONSTART". And when starting the script you could pass an empty string like -g ''
Related
I want to include a default option in my script where if the user uses this option, set the flag to true or it should be false by default. It seems that the script is not accepting false or true as boolean value. How can I make it boolean?
flag=
instructions() {
echo " -a File name" >&2
echo " -f optional boolean" flag=${flag:-false}
}
while getopts ":a:fi" option; do
case "$option" in
a ) file=$OPTARG;;
f ) flag=true;;
u )
instructions
;;
\?)
echo "Not valid -$OPTARG" >&2
instructions
;;
: ) echo "args required";;
esac
done
if [[ "$flag" != true || "$flag" != false ]]; then
echo "Not a boolean value"
fi
Check this, I made some fixes to your script (commented in the code) along with a proper formatting.
#!/bin/bash
# Set the default value of the flag variable
flag=false
instructions() {
echo "Usage: $0 [ -a FILE ] [ -f ]" >&2
echo " -a File name" >&2
echo " -f optional boolean flag=${flag:-false}" >&2
}
# If the script must be executed with options, this checks if the number of arguments
# provided to the script is greater than 0
if [ $# -eq 0 ]; then
instructions
exit 1
fi
while getopts ":a:fi" option; do
case "${option}" in
a )
file="$OPTARG"
;;
f )
flag=true
;;
i ) # "u" is not a valid option
instructions
exit 0
;;
\?)
echo "Option '-$OPTARG' is not a valid option." >&2
instructions
exit 1
;;
: )
echo "Option '-$OPTARG' needs an argument." >&2
instructions
exit 1
;;
esac
done
# Since a variable can't have 2 values assigned at the same time,
# you should use && (and) instead of || (or)
if [[ "$flag" != true ]] && [[ "$flag" != false ]]; then
echo "Not a boolean value"
fi
exit 0
I am running the below script, but it looks like the $filename or $srvname did not get the input value.
say for eg: ./test.sh -n abcd.net gives the output echo 'Filename or node name must be defined.'
it means that, the $srvname did not get the value "abcd.net", please advise am i doing anything wrong. ?
set -x
usage () {
echo "usage: $0 -n <nodename>"
echo "usage: $0 -f <filename>"
echo "usage: $0 -h <help>"
}
while getopts ":nfh:" opt; do
case "$opt" in
n) srvname="$OPTARG" ;;
f) filename="$OPTARG" ;;
h) # help
usage
exit 0
;;
:) echo "Error: -$OPTARG requires an argument"
usage
exit 1
;;
?) echo "Error: unknown option -$OPTARG"
usage
exit 1
;;
esac
done
function dosomecheck {
echo "do some checks"
}
if [ "$filename" != "" ] ; then
# read file
for x in `cat $filename` ; do
dosomecheck $x
done
fi
if [ "$srvname" != "" ] ; then
# read file
for x in $srvname ; do
dosomecheck $x
done
fi
Thanks in advance
Try doing:
while getopts ":n:f:h" opt;
because -n and -f takes argument while -h doesn't.
Hello I'm trying to find a way how to make getopts work with non of expected optional arguments
I have a script with optional arguments
script.sh [-a] [-b] [-c | -d] file
I have it working with -a..-d like this
while geopts abc:abd opt
do
case $opt in
a) do this ;;
b) do this ;;
...
.. etc
I want to make it so it can work without those arguments, so I can run it like this
script.sh file
Is there a way to make a new case option or do I need to do it other way, thanks for all help, im a beginner in bash.
I've done this kind of thing before:
declare -A have=([a]=false [b]=false [c]=false [d]=false)
while geopts :abcd opt; do
case $opt in
a) have[a]=true ;;
b) have[b]=true ;;
c) have[c]=true ;;
d) have[d]=true ;;
?) echo "illegal option: -$OPTARG"; exit 1;;
esac
done
shift $((OPTIND-1))
if ${have[c]} && ${have[d]}; then
echo "cannot give both -c and -d"
exit 1
fi
${have[a]} && do_a_stuff
${have[b]} && do_b_stuff
...
That case statement is a pretty egregious bit of cut'n'paste programming: tightening it up:
while geopts :abcd opt; do
case $opt in
a|b|c|d) have[$opt]=true ;;
?) echo "illegal option: -$OPTARG"; exit 1;;
esac
done
I have the following test script:
#! /bin/bash
USAGE="test.sh [-a] [-b] [-c | -d ]"
while getopts :abcd option
do
case $option in
a) OPT_A=1;;
b) OPT_B=1;;
c) OPT_C=1;;
d) OPT_D=1;;
*)
echo "$OPTARG is not a valid option."
echo "$USAGE"
exit 2;;
esac
done
shift $((OPTIND-1))
if [[ $OPT_C && $OPT_D ]]
then
echo "That's a no-no using options c and d together"
echo "$USAGE"
exit 2
fi
echo "The following options were set"
[[ $OPT_A ]] && echo " Option A was set"
[[ $OPT_B ]] && echo " Option B was set"
[[ $OPT_C ]] && echo " Option C was set"
[[ $OPT_D ]] && echo " Option D was set"
echo "And the file name is $1"
It will show you what options were set (and which ones weren't). It tests to make sure that -c and -d aren't used together.
Not 100% sure what you're asking for. But, you can see that instead of saying do this in my case statement, I'm merely setting variables that show what options were or weren't selected. That in itself my solve your problem.
I have one problem , when i select one option , for exemple ./test.sh -f it should print "mel" but it reads all code.
How does it enter the if condition and passes with other argument ?
if getopts :f:d:c:v: arg ; then
if [[ "${arg}" == d ]] ; then
d_ID=$OPTARG
eval d_SIZE=\$$OPTIND
else
echo "Option -d argument missing: needs 2 args"
echo "Please enter two args: <arg1> <arg2>"
read d_ID d_SIZE
echo "disc $d_ID $d_SIZE" >> $FILENAME
fi
if [[ "${arg}" == c ]] ; then
c_NOME="$OPTARG"
eval c_ID1=\$$OPTIND
eval c_ID2=\$$OPTINDplus1
eval c_FICHEIRO=\$$OPTINDplus2
else
echo "Option -c argument missing: needs 4 args"
echo "Please enter two args: <arg1> <arg2> <arg3> <agr4>"
read c_NOME c_ID1 c_ID2 c_FICHEIRO
echo "raidvss $c_NOME $c_ID1 $c_ID2 $c_FICHEIRO" >> $FILENAME
fi
if [[ "${arg}" == f ]] ; then
echo "mel"
fi
fi
You are using getopts parameters wrong.
if getopts :f:d:c:v: arg
means that -f will follow the value of parameter, like
-f 5
If you want just have -f (without value) you need to change it to
if getopts :fd:c:v: arg ; then
(I deleted the ':'). Also, I think you should better use while cycle and case statements.
See this example
while getopts fd:c:v: opt
do
case "$opt" in
f) echo "mel";;
d) discFunction "$OPTARG";;
c) otherFunction "$OPTARG";;
v) nop;;
\?) echo "$USAGE" >&2; exit 2;;
esac
done
shift `expr $OPTIND - 1`
FILE_LIST=$1
MOVE=0
while getopts "m" OPT; do
case $OPT in
m) MOVE=1 ;;
M) MOVE=1 ;;
*) echo "Invalid parameter." >&2; exit 1 ;;
esac
done
echo $MOVE
echo $FILE_LIST
I will pass optional argument ( -m/-M) and file list .
test.sh -m a.txt
its display 1 -m , but i am looking for 1 a.txt
Supost if test.sh a.xt
it should be diplsay 0 and a.txt
You need to shift the arguments.
MOVE=0
while getopts "mM" OPT; do
case $OPT in
M|m) MOVE=1
shift;;
*) echo "Invalid parameter." >&2; exit 1 ;;
esac
done
echo $MOVE
FILE_LIST=$1
echo $FILE_LIST
You can also combine m and M into one case.
If I understand right, you want the syntax for running the script to be something like:
./scriptname [-mM] firstfile [secondfile ...]
If this is correct, none of the other answers quite work; here's how I'd do it:
#!/bin/bash
# Parse command options
MOVE=0
while getopts "mM" OPT; do
case "$OPT" in
m|M) MOVE=1 ;;
*) echo "Invalid option." >&2; exit 1 ;;
esac
done
shift $(( OPTIND-1 )) # Remove options from the argument list
# Parse command arguments
if [[ $# -eq 0 ]]; then
echo "No files specified." >&2
exit 1
fi
FILE_LIST=( "$#" ) # Use an array in case of spaces in filenames
# Some examples of things to do with the results:
# Work with the specified files individually:
for FILE in "${FILE_LIST[#]}"; do
chmod g+w "$FILE"
done
# Work with the specified files as a group:
if (( MOVE == 1 )); then
mv "${FILE_LIST[#]}" "$DEST_DIR"
else
cp "${FILE_LIST[#]}" "$DEST_DIR"
fi
I do not exactly know what you want but Here are some code examples:
First example assumes that the filelist is given always after the -m option
while getopts "m:" OPT
do
case $OPT in
m)
echo "option m"
FILE_LIST = $OPTARG
;;
*)
echo "error"
;;
esac
done
echo $FILE_LIST
Or a different approach with a filelist not related to the -m option
while getopts "m:" OPT
do
case $OPT in
m)
echo "option m"
MOVE = 1
;;
*)
echo "error"
;;
esac
done
shift $(($OPTIND - 1))
FILE_LIST = $1
echo $FILE_LIST
Hope this suits your needs
You have to use $OPTARG value for this. Notice m:. The colon specifies that there are arguments passed to -m
#!/bin/bash
MOVE=0
while getopts "m:M:" OPT; do
case $OPT in
m|M) MOVE=1
FILE_LIST="$FILE_LIST $OPTARG"
;;
*) echo "Invalid parameter." >&2; exit 1 ;;
esac
done
shift $(( OPTIND-1 ))
[[ $MOVE != 1 ]] && FILE_LIST=$1
echo $MOVE
echo $FILE_LIST