I'm trying to add my own custom check to nagios.
I have successfully created a bash script, that is executable from nagios user.
The problem is that this script works fine from linux command line, but it's return the unknown status if runned by nagios ( returned in web gui ).
#!/bin/sh
while getopts ":q:c:w:h:u:p" optname
do
case "$optname" in "q") query=$OPTARG
;;
"c") CIRT=$OPTARG
;;
"w") WARN=$OPTARG
;;
"u") user=$OPTARG
;;
"p") pswd=$OPTARG
;;
"h") echo "Useage: check_SQLplus_query -u user -p password -w warning value -c cirtical value"
exit
;;
"?") echo "Unknown option $OPTARG"
exit
;;
":") echo "No argument value for option $OPTARG"
exit
;;
*) # Should not occur
echo "Unknown error while processing options"
exit
;;
esac
done
RETVAL=`sqlplus -s USER/PASSWORD#HOST:1521/DBNAME<<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
$query;
EXIT;
EOF`
if [ "$RETVAL" -le "$CIRT" ]
then
echo "OK - $RETVAL"
exit 0
elif [ "$RETVAL" -gt "$CIRT" ] && [ "$RETVAL" -le "$WARN" ]
then
echo "WARNING - $RETVAL"
exit 1
elif [ "$RETVAL" -gt "$WARN" ]
then
echo "CRITICAL - $RETVAL"
exit 2
else
echo "UNKNOWN - $RETVAL"
exit 3
fi
Actually the user, password are "coded" inside script, even if I've already set the getopt to make this script more flexible.
The idea is simple, use sqlplus to get a simple query that return only a number ( like the number of the row like my case ).
Bash line to start the script:
/usr/lib64/nagios/plugins/check_SQLplus_queryPrimavera.sh -q "select count(*) from ADMUSER_PM.REFRDEL" -w 6000000 -c 8000000
Related
This question already has answers here:
How do I parse command line arguments in Bash?
(40 answers)
Closed 2 years ago.
I'm writing a simple bash script and I would like it to accept parameters from the command line in any order.
I've browsed around the web and wrote a simple function with a case statement in a while loop. Right now, the 'any order' part works - but it only picks up the first parameter I set. I'm certainly doing something wrong but scripting is quite new to me and I hadn't been able to figure it out - your help would be greatly appreciated. The flags part of the script is as follows:
#Parameters - source,destination,credentials,bandwidth,timeout,port,help
flags () {
while test $# -gt 0; do
case "$1" in
-s|--source)
shift
if test $# -gt 0; then
export SOURCE=$1
else
echo "No source directory specified!"
exit 1
fi
;;
-d|--destination)
shift
if test $# -gt 0; then
export DESTINATION=$1
fi
;;
-c|--credentials)
shift
if test $# -gt 0; then
export CREDENTIALS=$1
fi
;;
-b|--bandwidth)
shift
if test $# -gt 0; then
export BANDWIDTH=$1
fi
;;
-t|--timeout)
shift
if test $# -gt 0; then
export TIMEOUT=$1
fi
;;
-p|--port)
shift
if test $# -gt 0; then
export PORT=$1
fi
;;
-h|--help)
shift
if test $# -gt 0; then
echo "Help goes here"
fi
;;
-l|--compression-level)
shift
if test $# -gt 0; then
export COMPRESS_LEVEL=$1
fi
;;
*)
break
;;
esac
done
}
flags "$#"
echo "source is $SOURCE, destination is $DESTINATION, credentials are $CREDENTIALS, bandwidth is $BANDWIDTH, timeout is $TIMEOUT, port is $PORT"
Ideally, some of those parameters would be mandatory, and others optional - but that's not a must.
How can I fix this script to accept any of those parameters (both long and short forms, ideally) in any order?
As noted in the comments, after you consume the argument (for example for credentials), you need another shift. You should be consistent in your error reporting for non-existent arguments. If you get -h or --help, you should simply print the help and exit; you should not test for more arguments. If help is requested, you give it and do nothing else. You should also echo errors to standard error: echo "message" >&2. Your messages should be prefixed with the script/program name: arg0=$(basename "$0" .sh) and echo "$arg0: message" >&2 etc.
Putting the changes together, you might come up with a script like this:
#!/bin/sh
arg0=$(basename "$0" .sh)
blnk=$(echo "$arg0" | sed 's/./ /g')
usage_info()
{
echo "Usage: $arg0 [{-s|--source} source] [{-d|--destination} destination] \\"
echo " $blnk [{-c|--credentials} credentials] [{-b|--bandwidth} bandwidth] \\"
echo " $blnk [{-t|--timeout} timeout] [{-p|--port} port] \\"
echo " $blnk [-h|--help] [{-l|--compression-level} level]"
}
usage()
{
exec 1>2 # Send standard output to standard error
usage_info
exit 1
}
error()
{
echo "$arg0: $*" >&2
exit 1
}
help()
{
usage_info
echo
echo " {-s|--source} source -- Set source directory (default: .)"
echo " {-d|--destination} destination -- Set destination"
echo " {-c|--credentials} credentials -- Set credentials"
echo " {-b|--bandwidth} bandwidth -- Set maximum bandwidth"
echo " {-t|--timeout} timeout -- Set timeout (default: 60s)"
echo " {-p|--port} port -- Set port number (default: 1234)"
echo " {-l|--compression-level} level -- Set compression level (default: 1)"
echo " {-h|--help} -- Print this help message and exit"
# echo " {-V|--version} -- Print version information and exit"
exit 0
}
flags()
{
while test $# -gt 0
do
case "$1" in
(-s|--source)
shift
[ $# = 0 ] && error "No source directory specified"
export SOURCE="$1"
shift;;
(-d|--destination)
shift
[ $# = 0 ] && error "No destination specified"
export DESTINATION="$1"
shift;;
(-c|--credentials)
shift
[ $# = 0 ] && error "No credentials specified"
export CREDENTIALS="$1"
shift;;
(-b|--bandwidth)
shift
[ $# = 0 ] && error "No bandwidth specified"
export BANDWIDTH="$1"
shift;;
(-t|--timeout)
shift
[ $# = 0 ] && error "No timeout specified"
export TIMEOUT="$1"
shift;;
(-p|--port)
shift
[ $# = 0 ] && error "No port specified"
export PORT="$1"
shift;;
(-l|--compression-level)
shift
[ $# = 0 ] && error "No compression level specified"
export COMPRESS_LEVEL="$1"
shift;;
(-h|--help)
help;;
# (-V|--version)
# version_info;;
(*) usage;;
esac
done
}
flags "$#"
echo "source is $SOURCE"
echo "destination is $DESTINATION"
echo "credentials are $CREDENTIALS"
echo "bandwidth is $BANDWIDTH"
echo "timeout is $TIMEOUT"
echo "port is $PORT"
Sample run (script name: flags53.sh):
$ sh flags53.sh -c XYZ -d PQR -s 123 -l 4 -t 99 -b 12 -p 56789
source is 123
destination is PQR
credentials are XYZ
bandwidth is 12
timeout is 99
port is 56789
$ sh flags53.sh -c XYZ --destination PQR -s 123 -l 4 --timeout 99 -b 12 --port 56789
source is 123
destination is PQR
credentials are XYZ
bandwidth is 12
timeout is 99
port is 56789
$ sh flags53.sh -c XYZ -h
Usage: flags53 [{-s|--source} source] [{-d|--destination} destination] \
[{-c|--credentials} credentials] [{-b|--bandwidth} bandwidth] \
[{-t|--timeout} timeout] [{-p|--port} port] \
[-h|--help] [{-l|--compression-level} level]
{-s|--source} source -- Set source directory (default: .)
{-d|--destination} destination -- Set destination
{-c|--credentials} credentials -- Set credentials
{-b|--bandwidth} bandwidth -- Set maximum bandwidth
{-t|--timeout} timeout -- Set timeout (default: 60s)
{-p|--port} port -- Set port number (default: 1234)
{-l|--compression-level} level -- Set compression level (default: 1)
{-h|--help} -- Print this help message and exit
$
Note that requested help can go to standard output instead of standard error, though sending the help to standard error would not be an egregious crime. The help gets the usage message and extra information about the meaning of each option. Noting defaults (and setting them) is a good idea too. It may not be necessary to export the settings — you could simply set the variables without an explicit export. You should really set the variables to their defaults before calling the flags function, or at the start of the flags function. This avoids accidentally inheriting exported values (environment variables). Unless, of course, you want to accept environment variables, but then your names should probably be given a systematic prefix appropriate for the script name. Most programs should have a --version or -V option (use -v for 'verbose', not for version). If the command does not accept any non-option (file name) arguments, add a check after the parsing loop and complain about unwanted arguments. If the command must have at least one non-option argument, check that instead. Do not report an error on receiving -- as an argument; terminate the checking loop and treat any remaining arguments as non-option arguments.
One residual problem — the shifts in the function affect the function's argument list, not the global "$#". You'd have to work out how to deal with that from this skeleton. I think I'd probably create an analogue to $OPTIND that reports how many arguments to shift to get to the non-option arguments. The code in the flags function should keep track of how many arguments it shifts.
That leads to the revised code:
#!/bin/sh
arg0=$(basename "$0" .sh)
blnk=$(echo "$arg0" | sed 's/./ /g')
usage_info()
{
echo "Usage: $arg0 [{-s|--source} source] [{-d|--destination} destination] \\"
echo " $blnk [{-c|--credentials} credentials] [{-b|--bandwidth} bandwidth] \\"
echo " $blnk [{-t|--timeout} timeout] [{-p|--port} port] \\"
echo " $blnk [-h|--help] [{-l|--compression-level} level]"
}
usage()
{
exec 1>2 # Send standard output to standard error
usage_info
exit 1
}
error()
{
echo "$arg0: $*" >&2
exit 1
}
help()
{
usage_info
echo
echo " {-s|--source} source -- Set source directory (default: .)"
echo " {-d|--destination} destination -- Set destination"
echo " {-c|--credentials} credentials -- Set credentials"
echo " {-b|--bandwidth} bandwidth -- Set maximum bandwidth"
echo " {-t|--timeout} timeout -- Set timeout (default: 60s)"
echo " {-p|--port} port -- Set port number (default: 1234)"
echo " {-l|--compression-level} level -- Set compression level (default: 1)"
echo " {-h|--help} -- Print this help message and exit"
# echo " {-V|--version} -- Print version information and exit"
exit 0
}
flags()
{
OPTCOUNT=0
while test $# -gt 0
do
case "$1" in
(-s|--source)
shift
[ $# = 0 ] && error "No source directory specified"
export SOURCE="$1"
shift
OPTCOUNT=$(($OPTCOUNT + 2));;
(-d|--destination)
shift
[ $# = 0 ] && error "No destination specified"
export DESTINATION=$1
shift
OPTCOUNT=$(($OPTCOUNT + 2));;
(-c|--credentials)
shift
[ $# = 0 ] && error "No credentials specified"
export CREDENTIALS=$1
shift
OPTCOUNT=$(($OPTCOUNT + 2));;
(-b|--bandwidth)
shift
[ $# = 0 ] && error "No bandwidth specified"
export BANDWIDTH=$1
shift
OPTCOUNT=$(($OPTCOUNT + 2));;
(-t|--timeout)
shift
[ $# = 0 ] && error "No timeout specified"
export TIMEOUT="$1"
shift
OPTCOUNT=$(($OPTCOUNT + 2));;
(-p|--port)
shift
[ $# = 0 ] && error "No port specified"
export PORT=$1
shift
OPTCOUNT=$(($OPTCOUNT + 2));;
(-l|--compression-level)
shift
[ $# = 0 ] && error "No compression level specified"
export COMPRESS_LEVEL="$1"
shift
OPTCOUNT=$(($OPTCOUNT + 2));;
(-h|--help)
help;;
# (-V|--version)
# version_info;;
(--)
shift
OPTCOUNT=$(($OPTCOUNT + 1))
break;;
(*) usage;;
esac
done
echo "DEBUG-1: [$*]" >&2
echo "OPTCOUNT=$OPTCOUNT" >&2
}
flags "$#"
echo "DEBUG-2: [$*]" >&2
echo "OPTCOUNT=$OPTCOUNT" >&2
shift $OPTCOUNT
echo "DEBUG-3: [$*]" >&2
echo "source is $SOURCE"
echo "destination is $DESTINATION"
echo "credentials are $CREDENTIALS"
echo "bandwidth is $BANDWIDTH"
echo "timeout is $TIMEOUT"
echo "port is $PORT"
There are other ways of writing the arithmetic if you wish to experiment. Don't use expr though.
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
Problem:
I need to make this bash script to choose based on the user inputs. Example how can i add choices? such that user just select from 1 to 3 and that is set in variable CLUSTER_NAME.
choices are test.com, try.com and me.com
Script
#!/bin/bash
sops_ops() {
sops --version
if [ "$?" -eq "0" ]; then
echo "proceed sops ops"
else
echo "check sops binary"
fi
read -p 'Enter cluster_NAME: = ' CLUSTER_NAME
test_environment="test.com"
test1_environment="test1.com"
test2_environment="test2.com"
case "${$CLUSTER_NAME}" in
prod.$test_environment) ;;
dev.$test1_environment) ;;
stage.$test2_environment) ;;
test.$test_environment) ;;
*) echo "Invalid option: ${CLUSTER_NAME}" 1>&2 && exit 1 ;;
if [ $CLUSTER_NAME = test.$test_env ];then
printf "got cluster $CLUSTER_NAME"
elif [ $CLUSTER_NAME = "test.test.com" ];then
printf "got dev cluster $CLUSTER_NAME"
echo "not found cluster"
else
echo "Environment not available"
fi
}
sops_ops
Question:
How do I do that?
Any help is appreciated!
I have a shell script that takes parameters, below is the code..
Right now it will only accept parameters if passed if called like this: script.sh --mode=load (or -m=load)
Is there a way to modify this so that it can be called with or without the "=" sign, so that I can call: script.sh --mode load (or -m load)
Ideally needs to work in pure bash as I don't have access to install additional tools, etc.
for i in "$#"
do
case $i in
-m=*|--mode=*)
MODE="${i#*=}"
if [[ $MODE =~ ^(dump|load)$ ]]; then
echo "" > /dev/null
else
bark "Invalid --mode set, set this to dump or load.";
exit 1
fi
;;
-p=*|--db-path=*)
DBPATH="${i#*=}"
;;
-d=*|--dump-dir=*)
DUMPDIR="${i#*=}"
;;
-l=*|--list-file=*)
TABLES="${i#*=}"
# check if file exists on disk
if [ -e $TABLES ]
then
echo "" >> /dev/null
else
bark "Table file not found!";
exit 1
fi
;;
-t=*|--tenant-name=*)
TENANT="${i#*=}"
# check if tenant is correct
if [[ $TENANT =~ ^($TENANT_LIST)$ ]]; then
echo "" >> /dev/null
else
bark "Tenant name does not match, aborting.";
exit 1
fi
;;
-s|--shared)
SHARED=YES
;;
*) usage # unknown option
;;
esac
done
My bash version:
bash --version
GNU bash, version 4.3.22(1)-release (powerpc-ibm-aix5.1.0.0)
Loop on $#. When $1 is "-m", do a shift. So in the next loop $1 will now be the argument to the -m option.
script.sh --mode load
# FIRST LOOP
$# is "--mode load"
$1 is "--mode"
shift
# SECOND LOOP
$# is "load"
$1 is "load"
This is also useful if you can specify many arguments instead of just one like you have right now. Error checking should be done to validate your argument values, and if a user did script.sh --mode with no other argument.
Don't reinvent the wheel.
If you're OK with just 1 character options, use the bash builtin getopts
#!/bin/bash
while getopts :m:p:d:l:t:s opt; do
case $opt in
m) mode=$OPTARG ;;
p) dbpath=$OPTARG ;;
d) dumpdir=$OPTARG ;;
l) tables=$OPTARG
# test file existence
;;
t) tenant=$OPTARG
# test tenant
;;
s) shared=YES ;;
:) echo "Missing argument for option -$OPTARG" >&2
exit 2
;;
*) echo "Invalid option -$OPTARG" >&2
exit 2
;;
esac
done
shift $((OPTIND - 1))
cat << SHOW_VARS
I have:
mode=$mode
dbpath=$dbpath
dumpdir=$dumpdir
tables=$tables
tenant=$tenant
shared=$shared
rest of args=$*
SHOW_VARS
Otherwise, you may be able to use the external getopt program to help parse your args. I don't have an AIX box to test on, so YMMV
tempargs=$(
getopt \
-o m:d:l:t:s \
--long mode:,db-path:,dump-dir:,list-file:,tenant-name:,shared \
-- "$#"
)
if [[ $? -ne 0 ]]; then echo "Error..." >&2; exit 2; fi
eval set -- "$tempargs"
while true; do
case $1 in
-m|--mode) mode=$2; shift 2;;
-p|--db-path) dbpath=$2; shift 2;;
-d|--dump-dir) dumpdir=$2; shift 2;;
-l|--list-file) tables=$2
# test file existence
shift 2
;;
-t|--tenant-name) tenant=$2
# test tenant
shift 2
;;
-s|--shared) shared=YES; shift;;
--) shift; break ;;
*) echo "Error..." >&2; exit 2 ;;
esac
done
I am using the following kind of bash code. I store some information within log file which name is defined in the bash script.
LOGNAME="/tmp/ETH"
LOG_FILE="${LOGNAME}.log"
function exit_error()
{
case "$1" in
100 )
echo "Bad arguments supplied - Enter help"
echo "Bad arguments supplied - Enter help" >> "${LOG_FILE}"
;;
101 )
echo "Illegal number of parameters"
echo "Illegal number of parameters" >> "${LOG_FILE}"
;;
* )
;;
esac
exit 1;
}
function current_status()
{
INT_STATUS=$(cat /sys/class/net/eth1/operstate)
echo "status : $INT_STATUS"
echo "status : $INT_STATUS" >> "${LOG_FILE}"
}
function connect_eth()
{
...
}
...
case "$1" in
current_status )
if [ "$#" -ne 1 ]
then
exit_error 101
else
current_status
fi
;;
connect_eth )
if [ "$#" -ne 1 ]
then
exit_error 101
else
connect_eth
fi
;;
read_MAC_addr )
if [ "$#" -ne 1 ]
then
exit_error 101
else
read_MAC_addr
fi
;;
read_IP_addr )
if [ "$#" -ne 1 ]
then
exit_error 101
else
read_IP_addr
fi
;;
* )
exit_error 100
;;
esac
exit 0;
I would like to modify the script in order to use the specified log name if no other log name is specified as last parameter. However, I would like to keep my "exit_error 101" in switch case which is based on the number of parameters passed to the script. Is there a way to do that ? Because I can not modify the $# variable.
It should be possible. Do something like this:
CMD="$1"
shift
# use provided logname or set to default if not found
LOGNAME="${1:-/tmp/ETH}
shift
LOGFILE="${LOGNAME}.log"
# now, since we shifted, you just have to check for $# -eq 0 to
# be sure there are no params left.
... your function definitions here ...
# exit 101 if there are some parameters left
if [ $# -ne 0 ]; then
exit_error 101
fi
case "$CMD" in
current_status)
current_status
;;
...
*)
exit_error 100
;;
esac
If you want more flexibility, you can always use getopts and named parameters. It is usually much easier to maintain.
And, if I were you, I would also centralize error handling before the case statement to avoir repeating the same check everywhere.