Tuesday, July 7, 2015

Shell script–Utility functions

Hello fellow DBAs, Oracle and Linux enthusiasts.

Today I'm going to share the script I use to "source" utility functions to the shell scripts I commonly use for my daily DBA tasks.

#!/bin/ksh
###########################
##
## File: utility_functions.ksh
##
## Author: Jesus Sanchez (jsanchez.consultant@gmail.com)
##
## Changelog:
## 2015-05-14 Jesus Sanchez Created this script
##
######################################################################
###############
## FUNCTIONS ##
###############
#####################
# Utility Functions #
#####################
##########################
#
# Function: continueQuestion
#
# Description:
# This function asks the user if all is good to continue
#
# Usage: continueQuestion
#
##############################################
function continueQuestion {
STEP=$1
ANSWER="NONE"
while [[ $ANSWER != "y" && $ANSWER != "Y" && $ANSWER != "n" && $ANSWER != "N" ]]
do
if [[ $ANSWER != "NONE" ]]
then
print "[ATTENTION] Please enter \"y\" or \"n\" without the double quotes and press <ENTER>"
print " "
fi
print -n "[INPUT] Do you want to continue? (y/n) <ENTER> for [y]: "
read ANSWER
if [[ -z $ANSWER ]]
then
ANSWER="y"
fi
done
if [[ $ANSWER = "y" || $ANSWER = "Y" ]]
then
return 0
elif [[ $ANSWER = "n" || $ANSWER = "N" ]]
then
exit -1
fi
}
##########################
#
# Function name: debugPrint
#
# Description:
# This function will print debug messages if the
# main script was called with the -debug option
#
# Usage: debugPrint <double-quoted message>
#
####################
function debugPrint {
if [[ $DEBUG -eq 1 ]]
then
TS=$(date +"%Y-%m-%d %H:%M:%S")
print "[DEBUG][${TS}] $1 "
fi
}
##########################
#
# Function name: msgPrint
#
# Description:
# This function will print debug messages if the
# main script was called with the -debug option
#
# Usage:
# msgPrint -<info|warning|error|critical|input> <double-quoted message>
# msgPrint -<blank|separator>
#
####################
function msgPrint {
type=""
case $1 in
"-blank") type="BLANK";;
"-critical") type="CRITICAL";;
"-error") type="ERROR";;
"-debug") type="DEBUG"
if [[ $# -eq 2 ]]
then
shift
caller=$1
fi;;
"-info") type="INFO";;
"-input") type="INPUT";;
"-notice") type="NOTICE";;
"-none") type="NONE";;
"-separator") type="SEPARATOR";;
"-title") type="TITLE";;
"-warning") type="WARNING";;
*) type="NONE"
esac
shift
message="$*"
# Print
if [[ ${type} = "BLANK" ]]
then
print " "
elif [[ ${type} = "DEBUG" ]]
then
if [[ $DEBUG -eq 1 ]]
then
ts=$(date +"%Y-%m-%d %H:%M:%S")
print "[$type][$ts][$caller] $message "
fi
elif [[ ${type} = "INPUT" ]]
then
print -n "[$type] $message: "
elif [[ ${type} = "SEPARATOR" ]]
then
print "----------------------------------------------"
elif [[ ${type} = "TITLE" ]]
then
SPLITTER="================================================="
print " "
print "$SPLITTER"
print "$message"
print "$SPLITTER"
print " "
elif [[ ${type} = "NONE" ]]
then
print "[ $message ]"
else
print "[$type] $message"
fi
}
##########################
#
# Function name: getArgs
#
# Description:
# This function provides the getopts functionality
# while allowing the use of long operations and list of parameters.
# in the case of a list of arguments for only one option, this list
# will be returned as a single-space-separated list in one single string.
#
# Pre-reqs:
# None
#
# Output:
# GA_OPTION variable will hold the current option
# GA_VALUE variable will hold the value (or list of values) associated
# with the current option
#
# Usage:
# You have to source the function in order to be able to access the GA_OPTIONS
# and GA_VALUES variables
# . getArgs $*
#
####################
function getArgs {
# Variables to return the values out of the function
typeset -a GA_OPTIONS
typeset -a GA_VALUES
# Checking for number of arguments
if [[ -z $1 ]]
then
msgPrint -warning "No arguments found"
msgPrint -info "Please call this function as follows: . getArgs \$*"
exit 0
fi
# Grab the dash
dash=$(echo $1 | grep "-")
# Looking for short (-) or long (--) options
isOption=$(expr index "$dash" "-")
# Initialize the counter
counter=0
# Loop while there are arguments left
while [[ $# -gt 0 ]]
do
if [[ $dash && $isOption -eq 1 ]]
then
(( counter+=1 ))
GA_OPTIONS[$counter]=$1
shift
else
if [[ -z ${GA_VALUES[$counter]} ]]
then
GA_VALUES[$counter]=$1
else
GA_VALUES[$counter]="${GA_VALUES[$counter]} $1"
fi
shift
fi
dash=$(echo $1 | grep "-")
isOption=$(expr index "$dash" "-")
done
# Make the variables available to the main algorithm
export GA_OPTIONS
export GA_VALUES
msgPrint -debug "Please check the GA_OPTIONS and GA_VALUES arrays for options and arguments"
# Exit with success
return 0
}
##########################
#
# Function name: setupLogs
#
# Description:
# This function will setup alog redirection pipe
# that will allow to write to console as well as to a logfile.
#
# Pre-reqs:
# Use the variable $LOGFILE in the main algorythm with
# full path and file name.
#
# Usage:
# setupLog <start|stop> <LOGFILE>
#
####################
function setupLogs {
if [[ $1 = "start" ]]
then
# set up redirects
exec 3>&1 4>&2
FIFO=/tmp/fifo.$$
[[ -e $FIFO ]] || mkfifo $FIFO
if [[ -e $LOGFILE ]]
then
tee -a $LOGFILE < $FIFO >&3 &
else
tee $LOGFILE < $FIFO >&3 &
fi
PID=$!
exec > $FIFO 2>&1
return 0
elif [[ $1 = "stop" ]]
then
PIDLIST=""
for PROCID in $(ps -ef | grep -v grep | grep "$$" | grep tee | tr -s [:space:] | cut -d" " -f2)
do
if [[ -z $(echo $PROCID | grep tee |tr -d [:space:]) && -z $PIDLIST ]]
then
PIDLIST="$PROCID"
else
PIDLIST="$PIDLIST $PROCID"
fi
done
msgPrint -debug "PIDLIST: $PIDLIST"
exec 1>&3 2>&4 3>&- 4>&-
wait $PIDLIST
rm -f /tmp/fifo.$$ && return 0
fi
}
export FIFO
##########################
#
# Function name: setupProfiling
#
# Description:
# This function will setup a log where timestamps will
# be kept for calculating profiling information
#
# Pre-reqs:
# None
#
# Usage:
# setupProfiling <start|stop> <SCRIPT|FUNCTION NAME>
#
####################
function profiling {
caller=${2}
profileLog=/tmp/${caller}_$$.tmp
if [[ $1 == "start" || $1 == "START" ]]
then
touch $profileLog
TS=$(date +"%s")
echo "$2:START:$TS" >> $profileLog
return 0
elif [[ $1 == "stop" || $1 == "STOP" ]]
then
TS=$(date +"%s")
echo "$2:STOP:$TS" >> $profileLog
RT=0
RTH=0
RTM=0
RTS=0
cat $profileLog
STARTTS=$(cat $profileLog | grep START | cut -d":" -f3)
ENDTS=$(cat $profileLog | grep STOP | cut -d":" -f3)
RT=$(( ENDTS-STARTTS ))
if [[ $RT -lt 60 ]]
then
RTS=$RT
elif [[ $RT -lt 3600 ]]
then
RTM=$( echo $RT / 60 | bc)
RT=$( echo $RT % 60 | bc )
RTS=$RT
else
RTH=$( echo $RT / 3600 | bc)
RT=$(( $RT % 3600 ))
RTM=$( echo $RT / 60 | bc)
RT=$( echo $RT % 60 | bc )
RTS=$RT
fi
rm -f $profileLog
return 0
fi
}

Let's add some explanation:

  • continueQuestion
    • This function is a simple "Continue? (y/n)" question. As this is used a lot in interactive scripts, seemed like a good idea for me to add it to the utility functions script.
  • debugPrint
    • For debugging, it adds the timestamp prior to the message. Allows you to keep track of what, where and when something is happening.
  • msgPrint
    • Allows you to format in several ways the output that you want to send to console/log file.

I hope you find this useful and makes your job better!

No comments:

Post a Comment