Tuesday, August 18, 2009

[Level 3] One shell a day, keep commands away~

The following the script is my template to create a new shell script.

with this helps,


regards,


Staley Huang


#!/usr/bin/bash
#/usr/bin/bash -xvu
# -x: print command and arguments after interpreted
# -v: print command and arguments before interpreted
# -f: no file globbing
# -u: treat unbound variable as error
# ex.
# a=1
# b=$a
# c=$d ( Error: unbound variable / parameter not set ... )
#
##Bash Note:
# while $1=null
# if [ -f $1] => true
# if [ -d $1] => true
# if [ -f "$1" ] => false
# if [ -d "$1" ] => false
#
################################################################
#
# Customize the setting following the key search
# [##**--]
#
# psedu code:
#
#
################################################################
#
# This template file is for ceating bash script program
# All copyright reserved by Stanley Huang
#
# __ script name ___________: [##**--(/shell/_shell_template.sh)] ## Do not remove '()' ##-- $sShellScriptName, absolution path
# __ purpose _______________: bash script template
# __ current version _______: [##**--(0.9.13 beta)] ## Do not remove '()' ##-- $sVersion, and below...
# __ base shell_temp Ver. __: 0.9.13 beta
# __ author ________________: Stanley Huang
# __ create date ___________: [##**--2006/12/12 10:45]
# __ included shell lib ____: /shell/inc/ : getLastField.sh, getInstanceDir.sh, [##**--]
# __ included perl lib _____: /shell/perlFuncs/ : [##**--] #-- $sIncShell
# __ included ucb lib ______: /usr/ucb/ : expr, [##**--] #-- $sPerlFuncs
# __ notes _________________: on this architecure, only have to modify the funcion 'runProc()' and the code with [##**--]
# __ modification history __:
# Version , Datetime , Author , Purpose
# -------------------------------------------------------------------
# v0.9 beta , 2006/12/12 10:45, Stanley Huang, Init
# v0.9.1 beta, 2006/12/14 23:30, Stanley Huang, Modify for $sPidFile with Instance Directory
# v0.9.2 beta, 2006/12/15 00:15, Stanley Huang, Modify for add check incShell & perlFuncs
# v0.9.3 beta, 2006/12/15 11:15, Stanley Huang, Modify for changing argument action with 'getopts'
# v0.9.4 beta, 2006/12/15 14:15, Stanley Huang, fix the bug for setCmdArgv
# v0.9.5 beta, 2006/12/16 00:30, Stanley Huang, Modify for $sLogFileName and kill PidFile while exit program normally
# v0.9.6 beta, 2006/12/17 23:30, Stanley Huang, Modify for shell_template layout
# v0.9.7 beta, 2006/12/20 22:45, Stanley Huang, add logSyslog function
# v0.9.8 beta, 2007/01/16 01:30, Stanley Huang, Modify for sShellScriptName and sVersion
# v0.9.9 beta, 2007/05/16 21:55, Stanley Huang, Add function pressEnterKey2Cont()
# v0.9.10 beta, 2007/07/17 07:05, Stanley Huang, Add function firstNonEmpty()
# v0.9.11 beta, 2007/07/17 07:05, Stanley Huang, Add function pressAnyKey2Cont()
# v0.9.12 beta, 2008/11/10 23:05, Stanley Huang, Add function pak2c(), modify function setCmdArgv(), for add case ':)' for without argument error
# v0.9.13 beta, 2009/07/23 10:22, Stanley Huang, Modify function firstNonEmpty() to verify more then 2 args and dynamic setting default value by getting environment variable "default_value"


#---------------- Trap -----------------
trap delPidFileAndExit 2
trap exitProg 0
#trap "echo 'hello'" 2


#---------------- Func -----------------


# firstNonEmpty $v1 $v2
_firstNonEmpty() {
sDefault="default value"
sReturn=$1
sNextValue=$2
sNextValue=${sNextValue:=$sDefault}
echo ${sReturn:=$sNextValue}
}


# firstNonEmpty "$v1" "$v2" "$v3" "$v4"
firstNonEmpty() {
sDefault=$default_value
while [ -z "$1" ] && [ $# -gt 0 ]
do
shift
done
if [ -z "$1" ]
then
[ ! -z "$sDefault" ] && echo $sDefault
else
echo "$1"
fi
}


# get data from shell, dependy on $lCmd
getDataFromShell() {
sVarName=$1
sVarValue=grep "^#@ $1=" $lCmd | head -1 | cut -d= -f2
}




# press enter key to continue
pressEnterKey2Cont() {
read -p "Press enter key to continue" sPressEnterKeyToContinue
}


# press any key to continue
pressAnyKey2Cont() {
read -p "Press enter key to continue" -n 1 sPressAnyKeyToContinue
echo ""
}
pak2c() {
read -p "Press enter key to continue" -n 1 x
echo ""
}


# set $sNow
setNow() {
sTimeMode=$1
local sFormat=""
case $sTimeMode in
1)
sFormat="+%Y/%m/%d %H:%M:%S"
;;
2)
sFormat="+%Y%m%d"
;;
3)
sFormat="+%Y%m%d%H%M%S"
;;
*)
sFormat="+%Y%m%d%H%M%S"
;;
esac
sNow=`date "$sFormat"`
}


# log into syslog
logSyslog() {
local sMesg=$1
local sPri=$2
local sTag=$3


if [ -z "$sMesg" ]
then
echo "Error log syslog without messsage!"
return
fi


if [ -z "$sPri" ]
then
sPri="user.err"
fi


if [ -z "$sTag" ]
then
sTag="ShellProgram"
fi


logger -p $sPri -t $sTag "Log from $sProgName : $sMesg"
}


# dependency with $bRunWithDot
exitProg() {
#echo $bIsRunWithDot
if [ $bIsRunWithDot -eq 1 ]
then
trap 2 # cancel trap 2
kill $$
else
exit 0
fi
}


# dependency with $bSetVarExplict, bSetDebug
setEnv() {
if [ $bSetVarExplict -eq 1 ]
then
set -u
export PS4='[${LINENO}]+ '
fi


export PS3='Select the item: ' # ref: showMenuSelect(){}


if [ $bSetDebug -eq 1 ]
then
set -x
fi
}


showMenu() {
declare sTitle=$1
declare sMenuList=$2
declare -i i=0
read -p "Press enter to continue..." x
clear
echo "Please select the no. of the item, or Ctrl+D to quit..."
echo $sTitle
for sMenuItem in $sMenuList
do
i=$i+1
echo "$i) $sMenuItem"
done
}


# no dependency
showMenuSelect() { # PS3
$sQuestion=$1
$sItemList=$2
$sDisplay=$3
$sEnding=$4


$sItemList="exit menu $sItemList"


echo "Please select the no. of the item, or Ctrl+D to quit..."
echo $sQuestion
select item in $sItemList
do
echo "$sDisplay : $item"
case $item in
exit)
break
;;
menu)
showMenu $sQuestion $sItemList
;;
template)
echo "template"
showMenu $sQuestion $sItemList
;;
*)
echo "you don't select any option try again..."
;;
esac
done
echo $sEnding
}


# dependency with $sProgName, $sVersion
getShellVersion() {
echo "The current version of the program ($sProgName) is: $sVersion"
}


# dependency with arguments($sOrigCmd), $sIncDir, $sProgName
setProgCmdName() {
if [ $0 == "/usr/bin/bash" ] || [ $0 == "bash" ]
##if [ $0 == $SHELL ] || [ $0 == "bash" ]
then
sSuffix="dot"
sProgName=$sShellScriptName
sCmd=`$sIncDir/getLastField.sh "$sProgName" "/"`
else
sSuffix="nom"
sProgName=$0
sCmd=`$sIncDir/getLastField.sh "$sProgName" "/"`
fi
}


# check Singleton
# only exist pidfile & process, return 0
# else return 1
#
# dependency with $sInstanceDir, $sCmd, $sSuffix, bSingleton, sPidFile, $sInstancePid
checkSingleton() {
#echo $sInstanceDir
#echo $sCmd
#echo $sSuffix
#exitProg
sPidFile=$sInstanceDir/$sCmd.$sSuffix
if [ $bSingleton -eq 1 ]
then
if [ -f "$sPidFile" ]
then
sInstancePid=`cat $sPidFile`
#if [ `ps -p $sInstancePid | grep -v PID | grep -c $sCmd` -eq 1 ]
if [ `ps -ef | grep $sInstancePid | grep -c $sCmd` -eq 1 ]
then
return 0
else
return 1
fi
else
return 1
fi
else
return 1
fi
}


# usage:
# showUsage [bNeedToShowDot(0/1)] [Original Command]
#
# dependency with arguments(0/1, $sOrigCmd), $bRunWithDot
showUsage() {
local lDot=""
local lCmd=""


if [ $1 -eq 1 ] || [ $2 == "." ]
then
lDot="."
fi


if [ $2 == "." ]
then
lCmd=$3
else
lCmd=$2
fi




#if [ $bShowDot -eq 1 ]
#then
# lDot="."
# #lCmd=$1
##else
# #lCmd=$0
#fi


##**--
## option => ":dhvl:", $sGetOpts
#echo $sGetOpts
echo "Usage:"
echo " $lDot $lCmd -dhv -l [ Output Log Filename ]"
echo "ex."
echo " $lDot $lCmd -v"


if [ $bDetail -eq 1 ]
then
#echo "The option description:"
#echo "-d: debug mode"
#echo "-h: help manual"
#echo "-v: display script version"
#echo "-l: setting log file name"
cat <&2 # PS. cat <<-EOF, the sign of eof is "EOF or EOF"
The option description:
-d: debug mode
-h: help manual
-v: display script version
-l: setting log file name
EOF
fi
}

# dependency with $sIncShell, $sIncDir
checkIncShell() {

local sLackOfShellNo=0

for sIncShellItem in $sIncShell
do
if [ ! -f "$sIncDir/$sIncShellItem" ]
then
echo "Lack Shell Library ($sIncDir/$sIncShellItem) !!!"
let "sLackOfShellNo=$sLackOfShellNo+1"
fi
done

if [ $sLackOfShellNo -gt 0 ]
then
echo "Total Shell Library Lacks: $sLackOfShellNo ."
echo "Exit program."
exitProg
fi
}

# dependency with $sPerlFuncs, $sPerlFuncsDir
checkPerlFuncs() {

local sLackOfPerlNo=0

for sPerlFuncsItem in $sPerlFuncs
do
if [ ! -f "$sPerlFuncsDir/$sPerlFuncsItem" ]
then
echo "Lack Perl Library ($sPerlFuncsDir/$sPerlFuncsItem) !!!"
let "sLackOfPerlNo=$sLackOfPerlNo+1"
fi
done

if [ $sLackOfPerlNo -gt 0 ]
then
echo "Total Perl Library Lacks: $sLackOfPerlNo ."
echo "Exit program."
exitProg # if use . , exit will cause the terminal closed.
fi
}

# dependency with $sRunWithDot
checkShellBase() {
local sReturn=""

if [ $bRunWithDot -eq 1 ]
then
if [ $0 == "/usr/bin/bash" ] || [ $0 == "bash" ]
## if [ $0 == $SHELL ] || [ $0 == "bash" ]
then
bIsRunWithDot=1
sReturn=1
else
bIsRunWithDot=0
echo "have to run this program with '.'"
showUsage 1 $sOrigCmd
sReturn=0
fi
else
if [ $0 == "/usr/bin/bash" ] || [ $0 == "bash" ]
## if [ $0 == $SHELL ] || [ $0 == "bash" ]
then
bIsRunWithDot=1
else
bIsRunWithDot=0
fi
sReturn=1
fi

return $sReturn
}

# dependeny with showUsage(), exitProg()
checkCmdArgv() {
# [##**--]
if [ -z "$sLogFileName" ]
then
echo "Error without assign the logfile (-l)"
showUsage
exitProg
elif [ ! -f "$sLogFileName" ]
then
touch $sLogFileName
fi
}

# dependency with $sRunWithDot, showUsage(), exitProg(), checkCmdArgv()
setCmdArgv() {
# [##**--]
local lOptionsCount=0
sGetOpts=":dhvl:"
while getopts $sGetOpts OPTION
# PS. ':'d => not display error message while the option is out of range...
do
case $OPTION in
d)
set -x
;;
h)
bDetail=1
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
;;
v)
getShellVersion
exitProg # if use . , exit will cause the terminal closed.
;;
l)
if [ `/usr/ucb/expr substr $OPTARG 1 1` == "/" ]
then
declare sLogFileName=$OPTARG
else
declare sLogFileName=`pwd`/$OPTARG
fi
;;
\?)
echo "No such option ($OPTARG)..."
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
;;
:)
echo ":)The option ($OPTARG) without assigning value..."
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
;;
*)
### never reach here ###
echo "*)The option ($OPTARG) without assigning value..."
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
;;
esac
done

let "lOptionsCount=$OPTIND-1"
if [ $lOptionsCount -eq 0 ]
then
echo "Please use this command with arguments..."
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
fi

checkCmdArgv
}

delPidFileAndExit() {
if [ -f "$sPidFile" ]
then
rm $sPidFile
fi
exitProg
}

# dependency with $sPidFile, $sWorkingDir, delPidFileAndExit()
runProc() {
if [ $bSingleton -eq 1 ]
then
echo "sPidFile="$sPidFile
echo $$ > $sPidFile
fi

##-------------------------------------------------------------------------------------------------

# [##**--]
declare -i count=0
while true
do
count=$count+1
if [ $count -gt 5 ]
then
break # exit while loop
fi
setNow 1
echo "[$$] $sNow" >> $sLogFileName
logSyslog "[$$] $sNow" "user.err" "ShellProgram"
sleep 3
done

##-------------------------------------------------------------------------------------------------

delPidFileAndExit
}


##[##**--], verify for global setting variables
#declareSysVariables() {

# init variables
# do not set the variable with readonly, cannot revoke the attribute back
# sh not support declare, so cannot run sh /shell/_shell_template.sh
#

declare -i bSetVarExplict=1
declare -i bSetDebug=0

declare sShellScriptName="/shell/_shell_template.sh" # absoluted path # [##**--]
#declare sShellScriptName=`grep "^#" $0 | grep "__ script name __" | cut -d'(' -f2 | cut -d')' -f1`
#if [ -z "$sShellScriptName" ]
#then
# sShellScriptName=`grep "^#" $1 | grep "__ script name __" | cut -d'(' -f2 | cut -d')' -f1`
#fi

declare sVersion=`grep "^#" $sShellScriptName | grep "__ current version __" | cut -d'(' -f2 | cut -d')' -f1`
#if [ -z "$sVersion" ]
#then
# sVersion=`grep "^#" $1 | grep "__ current version __" | cut -d'(' -f2 | cut -d')' -f1`
#fi

declare -i bRunWithDot=1 ##**--
declare -i bSingleton=1
declare sIncDir=/shell/inc
declare sPerlFuncsDir=/shell/perlFuncs
declare sWorkingDir=`pwd`
declare sIncShell="getLastField.sh getInstanceDir.sh"
declare sPerlFuncs=""
declare sOrigCmd="$0 $@"
declare sPara=$@
declare -i bDetail=0
declare sNow=""

# pre-define variables for checkSingleton()
declare sPidFile=""

# pre-define variables for setProgCmdName()
declare sSuffix=""
declare sProgName=""
declare sCmd=""


# pre-define variables for checkShellBase()
declare -i bIsRunWithDot=0

setProgCmdName $sOrigCmd # dependency with $sIncDir, $sSuffix, $sProgName, $sCmd
declare sInstanceDir=`$sIncDir/getInstanceDir.sh $sProgName`

declare sLogFileName=$sInstanceDir/$sCmd.log

#}

## [ declare ]
## declare option:
## -a: array
## -f: function
## -F: display function name but not the definition
## -i: integer
## -r: readonly
## -x: export
## ex.
## declare -ir nVar=123 # set variable as integer and readonly
## declare -x sVar="abc" # export to global environment
## declare -p nVar # display var attributes

####################################################################
#
# Add Extra Variables Below
#
####################################################################

#declareCustVariables() {
# [##**--]
#echo ""
#}

####################################################################
#
# Add Extra Functions Below
#
####################################################################

#---------------- Env ------------------

# init Environment
export LC_ALL=C

#---------------- Main -----------------


# declare system variables
#declareSysVariables

# declare cutomize variables
#declareCustVariables

# dependency with $bSetVarExplict, bSetDebug
setEnv

# no dependency
setCmdArgv $sPara

# dependency with $sIncShell, $sIncDir
checkIncShell
# dependency with $sPerlFuncs, $sPerlFuncsDir
checkPerlFuncs

# dependency with $sRunWithDot
checkShellBase
sReturn=$?

if [ $sReturn == '1' ]
then
# dependency with $sInstanceDir, $sCmd, $sSuffix, bSingleton, sPidFile, $sInstancePid
checkSingleton
sReturn=$?

if [ $sReturn == '1' ]
then
# dependency with $sPidFile, $sWorkingDir
#runProc $sPara
runProc
else
echo "Limited process with singleton, please check the instance pid file & process"
echo "instance pid file ($sPidFile), process ($sInstancePid)"
exitProg # if use . , exit will cause the terminal closed.
fi
fi


exitProg
exitProg
#--------------------------------------------------------------------
## Data for shell, begin with #@.
#@ username=root
#@ password=root123