I'm trying to figure out checking validation if they did not pass option -d option give error. Did the user gave me right arguments if not give error. Did user provide any arguments if not give error. Basically validation and it gives out errors . User has to put argument -d with option u- or -p but not both
do_p=0 # initialize variables
do_u=0
random_file=””
while getopts "d:uph?" option; do
case $option in
d)
random_file=$OPTARG
;;
u)
do_u=1
;;
p)
do_p=1
;;
h)
Help
exit;;
\?) echo "Error: Invalid option"
exit;;
esac
done
**#Validations**
# Does the file exist
if [[ ! -f device_file ]]; then
echo "Error: The file $device_file does not exist."
exit 1
fi
I was checking online one of the ways would be if statement
by #Validation would this work??
if [ ! -d "$device_file" ]; then
echo "pass in argument"
exit 0
fi
if [ d"${OPTARG:0:1}" == "d-" ]; then
echo "did not pass in option -U or -P"
exit 0
Well firstly, you don't exit 0 for error, you exit >=1, and you write error messages to standard error.
You're also testing -d which is a directory, but calling it a "device file" in the script, which sounds wrong, but I'll let you figure that out.
The first statement looks vaguely right, but I would prefer this:
[ "$device_file" ] || { echo "missing -d device_file argument" 1>&2 ; exit 1 ; }
[ -d "$device_file" ] || { echo "$device_file is not a directory" 1>&2 ; exit 2 ; }
For the 3rd thing you have there, it doesn't look right to me, but I can't be botherered to dig around and figure out what it does. If it were me, I wouldn't initialise do_provision and do_unprovision, I'd just set them to true if found. Then I'd write:
[ "$do_provision" -o "$do_unprovision" ] || { echo "must provide -u or -p" 1>&2 ; exit 3 ; }
Related
I have a bash script "domain-ssl-status.sh". I need a script with two arguments so that I could run the script in the following way:
./domain-ssl-status.sh cname.domain.com status|unobtained|obtained|error
domainName and status are my 2 arguments
domainName=$1 and status=$2
I have tried creating a status_map using a case statement, but no luck!! I have also seen other hints on here but mine never seems to work. My sql statement includes SELECT * FROM DomainSSL WHERE domainName='cname.domain.com' and I'm still stuck.
A rough pass at a rewrite -
#!/bin/bash
domainName=$1
status=$2
echo "Verifying domain"
case status in
$status) ping -c 1 $domainName || {
echo "Cannot ping $domainName" >&2
exit 1
} ;;
*) echo "Invalid argument '$status'" >&2
exit 1 ;;
esac
sql="SELECT * FROM DomainSSL WHERE domainName='$domainName'"
mssql -f csv -c ~/applications/mssql/mssql.json -q "$sql" # mark here
rc=$?
if (( rc )) # nonzero
then echo "FAIL: rc $rc on [$sql]" >&2
else echo "SUCCESS: $sql"
fi
You might also want to try saving the stdout and stderr for later parsing.
Rewriting from # mark above,
mssql -f csv -c ~/applications/mssql/mssql.json -q "$sql" >ok 2>oops
rc=$?
if (( rc )) # nonzero
then echo -e "FAIL: rc $rc on [$sql]:\n$(<oops)" >&2
case "$(grep SQLSTATE oops)" in
*ER_DUP_KEY*) : code to handle duplicate keys error ;;
# any other errors you choose to handle . . .
*) : code for bailing on errors you don't care to handle ;;
esac
else echo "SUCCESS: $sql"
fi
c.f. the mysql documentation here
This is just a general template. Hope it helps. Feel free to ask for clarification.
I'm beginning to experiment with getopts but am running into a few errors. When I enter an invalid option such as -A the program output is not what it needs to be.
#!/bin/bash
function usage() {
echo "Usage: $0 -h [database host] -d [test database name]"
exit 1
}
while getopts “:h:d:” opt; do
case ${opt} in
h)
db_host=$OPTARG
;;
d)
test_db=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" 1>&2
usage
exit 1
;;
:)
echo “Option -$OPTARG requires an argument.” 1>$2
usage
exit 1
;;
esac
done
shift $((OPTIND-1))
if [ -z $db_host ] || [ -z $test_db ]; then
usage
else
echo "Your host is $db_host and your test database is $test_db."
fi
Example program output:
./opt.sh: illegal option -- A
Invalid option: -
Usage: ./opt.sh -h [database host] -d [test database name]
So, basically two questions:
1) I want to get rid of this first error message altogether. I want to provide my own error messages.
2) Why isn't my script producing "Invalid option: -A" instead of just "Invalid option: -"
You have the wrong types of quotes around the options argument to getopts, they're "curly quotes" instead of ASCII double quotes. As a result, : wasn't the first character of the options, so you weren't getting silent error reporting.
Change it to
while getopts ':h:d:' opt; do
Having bash script as follows
#! /bin/bash
usage()
{
echo -e "need help!"
}
while getopts ":a:b:h" OPTION
do
case $OPTION in
a)
printf "a option with value %s\n" $OPTARG
;;
b)
printf "b option with value %s\n" $OPTARG
;;
h)
usage
;;
?)
echo -e "No option selected"
;;
esac
done
exit 0
Above script run fine with different option but i wanted to extend it to not allow to pass multiple option at same time like as following argument
$ ./test.bash -a 1 -b 2
a option with value 1
b option with value 2
should be not valid means some way it give me error like wrong syntax i achieved it by as follows but it seems to long it is as follow
#! /bin/bash
usage()
{
echo -e "need help!"
}
let "a_count=0"
let "b_count=0"
MY_ARG=""
while getopts ":a:b:h" OPTION
do
case $OPTION in
a)
let a_count=1
MY_ARG=$OPTARG
;;
b)
let b_count=1
MY_ARG=$OPTARG
;;
h)
usage
;;
?)
echo -e "No option selected"
;;
esac
done
[[ $a_count -eq 1 ]] && [[ $b_count -eq 1 ]] && echo "wrong command sytax" && exit 0
[[ $a_count -eq 1 ]] && printf "a option with value %s\n" $MY_ARG
[[ $b_count -eq 1 ]] && printf "b option with value %s\n" $MY_ARG
exit 0
run like
$ ./test.bash -a 1 -b 2
wrong command sytax
But i want to finish validation in while..loop of getopts. Also this validation not works for following command
./test.bash -a -b
a option with value -b
any one have batter idea how to use getopts for this type validation?
you've almost got it. The : after the a and after the b say that they take an argument, so your example with -a -b is actually valid, saying "There is option a with value -b".
If you really just want "-a or -b and then an argument", you probably don't need getopts at all, but should do:
[ "$1" == "-a" ] && printf "a option with value %s\n" $2
[ "$1" == "-b" ] && printf "b option with value %s\n" $2
any one have batter idea how to use getopts for this type validation?
well, actually, you're explicitly telling geptopts that -a and -b are not boolean parameters, but parameters that take an extra argument. The argument parser cannot tell whether the argument following -a is a parameter or its own argument, and thus they consider [-a ] [-b ] as syntax.
The best way, would actually be to have a different boolean parameter that matches the use case when you do not want an argument for -a and -b.
Though, it won't help you with your issue trying to have parameters with argument or boolean, but for the argument syntax checking you can try docopt which has a nicer way to create command line interface. You focus on doing the --help documentation, it parses it to build your parameter/argument parser. e.g.:
eval "$(docopts -V - -h - : "$#" <<EOF
Usage: myscript [(-a <foo> | -b <bar> | -abool | -bbool)]
-a <foo> The A option.
-b <bar> The B option.
-abool The A bool
-bbool The B bool
--help Show help options.
--version Print program version.
----
myscript 0.0.0
Copyright (C)20.. Your Name
License...
)"
if $a ; then
echo "a option! with $a"
fi
if $b ; then
echo "b option! with $b"
fi
if $abool ; then
echo "abool option!"
fi
if $bbool ; then
echo "bbool option!"
fi
This is not quite perfect because it will always process the first switch, but it does place an exit inside the while loop which is in keeping with your design requirement. It may give you an idea how to finish it.
#!/bin/bash
usage()
{
echo -e "need help!"
}
while getopts "a:b:h" OPTION
do
case $OPTION in
a)
aflag=1
aval=$OPTARG
if [ ! -z "$bflag" ]
then
printf "ERROR: cant use both -a and -b\n"
exit 1
fi
;;
b)
bflag=1
bval=$OPTARG
if [ ! -z "$aflag" ]
then
printf "ERROR: cant use both -a and -b\n"
exit 1
fi
;;
h) usage ;;
?) printf "ERROR" ; exit 1 ;;
esac
done
if [ ! -z "$aflag" ]
then
printf "a option with value %s $aval\n"
elif [ ! -z "$bflag" ]
then
printf "b option with value %s $bval\n"
fi
exit 0
If you still want to use the getopts I would use bash built-in variable for the arguments count $# to detect wrong number of arguments passed:
#! /bin/bash
usage()
{
echo -e "need help!"
}
# Check if number of arguments is greater than 2 as "-a1" (one arg) and "-a 2" are correct.
# You might want to check for other wrong inputs.
if [ $# > 2 ]
then
echo "Some warning t o the user or"
usage
exit 1
fi
while getopts ":a:b:h" OPTION
do
case $OPTION in
a)
printf "a option with value %s\n" $OPTARG
;;
b)
printf "b option with value %s\n" $OPTARG
;;
h)
usage
;;
?)
echo -e "No option selected"
;;
esac
done
exit 0
I have a script which should be run as either one of these two:
script.sh -t TYPE
script.sh -t TYPE -f FILE
If it is run without a -t flag I want it to error and exit.
If it is run with a -t flag I want to grab the value and store it in a
variable called "$TYPE" and print "JUST $TYPE"
If it is run with a -f flag I want it grab the value and store it in a variable called
"$FILE" and print "$TYPE and $FILE"
From information and tutorials on both here and the internet generally this is the closest I can get. Can anyone help me put in the second conditional into this existing code?
while getopts ":t:" opt; do
case $opt in
a)
echo "JUST $OPTARG" >&2
;;
\?)
echo "Error - Invalid type argument" >&2
exit 1
;;
:)
echo "Error - No type argument" >&2
exit 1
;;
esac
done
I think you get confused how you should handle command line arguments.
The common way is that the processing of all arguments precedes the actual job of the program/script.
Further more (related to getopts) if an option is appended by a colon, that indicates that the option is expected to have an argument.
Your case statement looks overpopulated too. You don't need to test for a colon and a question mark. The whole testing can be put after the while loop
I would do it like this
#!/bin/bash
unset TYPE
unset FILE
#uncomment if you want getopts to be silent
#OPTERR=0
while getopts "t:f:" opt; do
case $opt in
t)
TYPE=$OPTARG
echo "JUST $OPTARG"
;;
f)
FILE=$OPTARG
;;
esac
done
if ! test "$TYPE" ; then
echo "-t is obligatory"
exit 1
fi
if test "$TYPE" && test "$FILE" ; then
echo "$TYPE and $FILE"
fi
Have a look at this:
TYPE=""
FILE=""
while getopts "t:f:" opt; do
case $opt in
t) TYPE="$OPTARG"
;;
f) FILE="$OPTARG"
;;
esac
done
if [ -z "$TYPE" ]; then
echo "No -t. Bye."
exit 1 # error
else
if [ -n "$FILE" ]; then
echo "$TYPE and $FILE"
else
echo JUST $TYPE
fi
fi
I want to write a simple check upon running mkdir to create a dir. First it will check whether the dir already exists, if it does, it will just skip. If the dir doesn't exist, it will run mkdir, if mkdir fails (meaning the script could not create the dir because it does not have sufficient privileges), it will terminate.
This is what I wrote:
if [ ! -d "$FINALPATH" ]; then
if [[ `mkdir -p "$FINALPATH"` -ne 0 ]]; then
echo "\nCannot create folder at $FOLDERPATH. Dying ..."
exit 1
fi
fi
However, the 2nd if doesn't seem to be working right (I am catching 0 as return value for a successful mkdir). So how to correctly write the 2nd if? and what does mkdir returns upon success as well as failure?
The result of running
`mkdir -p "$FINALPATH"`
isn't the return code, but the output from the program. $? the return code. So you could do
if mkdir -p "$FINALPATH" ; then
# success
else
echo Failure
fi
or
mkdir -p "$FINALPATH"
if [ $? -ne 0 ] ; then
echo Failure
fi
The shorter way would be
mkdir -p "$FINALPATH" || echo failure
also idiomatic:
if mkdir -p "$FINALPATH"
then
# .....
fi
Likewise you can while .....; do ....; done or until ......; do ......; done
Just for completeness, you can exit by issuing:
mkdir -p "$FINALPATH" || { echo "Failure, aborting..." ; exit 1 ; }
Braces are necessary, or else exit 1 would execute in both cases.
Or you can create an abort function like:
errormsg()
{
echo "$1"
echo Aborting...
{ exit 1 ; }
}
And then just call it by issuing:
mkdir -p "$FINALPATH" || errormsg "Failure creating $FINALPATH"
Edited:
Braces, not parenthesis, as parenthesis only exit the subshell.
( Thanks #Charles Duffy )
A function to write a message and exit