!http://www.sun.com/bigadmin/home/images/bigadminHeaderWikiThumb.jpg!
{section:border=false}{column:width=25%}
{include:TOC for BigAdmin}
{column}{column:width=45%}
One feature of ksh not commonly known is the use of conditional function definitions in ksh. The general syntax for such definitions is
{code}
if [ <condition> ] ; then
function <functionname> {
<functionbody>
}
fi
{code}
Or\\
{code}
[ <condition> ] && function <functionname> {
>functionbody>
}
{code}\\
This feature is very handy if you must write scripts that are usable on various Unix variants (like Solaris, AIX, Linux, etc).
For example one time I had to adapt a script written for AIX to Solaris so that it runs on AIX and Solaris. This script used the AIX commands mknfsexp and rmnfsexp. mknfsexp and rmnfsexp are used in AIX to create or remove NFS shares:
{noformat}
Description from the mknfsexp man page:
The mknfsexp command takes the flags and parameters specified and constructs a line that is
syntactically correct for the /etc/exports file. If this command is invoked with the -B flag, an
entry will be added to the /etc/exports file and the exportfs command is invoked to export the
directory specified. Alternatively, the -I flag adds an entry to the exports file and does not
export the directory, or the -N flag does not add an entry to the exports file but does export the
directory.
{noformat}
{noformat}
Description from the rmnfsexp man page:
The rmnfsexp command removes an entry from the exports list for NFS clients. The rmnfsexp command
starts the exportfs command to unexport the specified directory. If an entry exists in the
/etc/exports file, that entry is removed.
{noformat}
Unfortunately these commands do not exist on Solaris. So the question was: How to do this on Solaris?
One solution is to rewrite the parts of the script that uses these commands. The disadvantage of this method is that you're changing a working script and you must test it again after implementing your changes to make sure it still works the way it worked before.
Another solution is to create the commands mknfsexp and rmnfsexp on Solaris (either as scripts or binaries). But doing it this way you must ensure, that these new commands exist on every Sun machine on which your script should run.
A much better solution is to define the missing functions in the script itself. This way you don't need to change the logic of the existing script and you do not have to take care to copy additional scripts/binaries to the machine running Solaris on which your script should run. But you must make sure, that your new function is only called on Solaris (and not on AIX where these functions are not needed) and therefor we use a conditional definition:
{code}
# define functions missing in Solaris
#
# get the current OS
#
OS="$( uname -ns)"
#
#
[ "${OS}"x = "SunOS"x ] && function mknfsexp {
typeset DIR_TO_EXPORT="" CLIENTS=
while [ "$1"x != ""x ] ; do
case $1 in
-d ) DIR_TO_EXPORT=$2; shift ;;
-r ) CLIENTS="$( echo $2 | tr "," ":" )"; shift ;;
esac
shift
done
if [ "${DIR_TO_EXPORT}"x != ""x -a "${CLIENTS}"x != ""x ] ; then
# check /etc/dfs/dfstab
typeset SHARE_COMMAND="share -F nfs -o anon=0,rw=${CLIENTS} ${DIR_TO_EXPORT}"
grep -v "^#" ${DFS_TAB_FILE} | egrep " ${DIR_TO_EXPORT} | ${DIR_TO_EXPORT}$" >/dev/null || echo ${SHARE_COMMAND} >>${DFS_TAB_FILE}
showmount -e | grep "^${DIR_TO_EXPORT} " >/dev/null || ${SHARE_COMMAND} || CheckRC 3 "Warning" "Warning: Error sharing the directory \"${DIR_TO_EXPORT}\" \n\n"
fi
}
#
# rmnfsexp -d "$to_delete"
#
[ "${OS}"x = "SunOS"x ] && function rmnfsexp {
typeset DIR_TO_EXPORT=""
while [ "$1"x != ""x ] ; do
case $1 in
-d ) DIR_TO_EXPORT=$2; shift ;;
esac
shift
done
if [ "${DIR_TO_EXPORT}"x != ""x ] ; then
# delete the share
showmount -e | grep "^${DIR_TO_EXPORT} " >/dev/null && unshare ${DIR_TO_EXPORT} || \
CheckRC 3 "Warning" "Warning: Error unsharing the directory \"${DIR_TO_EXPORT}\" \n\n"
# check /etc/dfs/dfstab
TMPFILE="/var/tmp/$( basename $0 ).$$"
grep -v "^#" ${DFS_TAB_FILE} | egrep " ${DIR_TO_EXPORT} | ${DIR_TO_EXPORT}$" >/dev/null
if [ $? -eq 0 ] ; then
grep -v "^#" ${DFS_TAB_FILE} | egrep -v " ${DIR_TO_EXPORT} | ${DIR_TO_EXPORT}$" >${TMPFILE}
cp ${DFS_TAB_FILE} ${DFS_TAB_FILE}.$$ || \
CheckRC 4 "ERROR" "Can not create a backup of the /etc/dfstab (Backupfile is \"${DFS_TAB_FILE}.$$\")"
cp ${TMPFILE} ${DFS_TAB_FILE} || \
CheckRC 4 "ERROR" "Can not change /etc/dfstab (Backupfile is \"${DFS_TAB_FILE}.$$\")"
fi
fi
}
# Note: CheckRC is another function defined in the script not shown here.
# here comes the rest of the existing script without any other changes
{code}
As can be seen in the example above you only need to implement the functionality of the missing function that is used in the script. You don't have to care about the other functionality of the emulated command because the function is only used by your script.
This is only one example where conditional function definitions are useful - I'm sure there are many situations where this functionality of ksh is very useful.
{column}
{column:width=25%}
{include: Links for BA Scripts}
{column}
{section}
{section:border=false}{column:width=25%}
{include:TOC for BigAdmin}
{column}{column:width=45%}
One feature of ksh not commonly known is the use of conditional function definitions in ksh. The general syntax for such definitions is
{code}
if [ <condition> ] ; then
function <functionname> {
<functionbody>
}
fi
{code}
Or\\
{code}
[ <condition> ] && function <functionname> {
>functionbody>
}
{code}\\
This feature is very handy if you must write scripts that are usable on various Unix variants (like Solaris, AIX, Linux, etc).
For example one time I had to adapt a script written for AIX to Solaris so that it runs on AIX and Solaris. This script used the AIX commands mknfsexp and rmnfsexp. mknfsexp and rmnfsexp are used in AIX to create or remove NFS shares:
{noformat}
Description from the mknfsexp man page:
The mknfsexp command takes the flags and parameters specified and constructs a line that is
syntactically correct for the /etc/exports file. If this command is invoked with the -B flag, an
entry will be added to the /etc/exports file and the exportfs command is invoked to export the
directory specified. Alternatively, the -I flag adds an entry to the exports file and does not
export the directory, or the -N flag does not add an entry to the exports file but does export the
directory.
{noformat}
{noformat}
Description from the rmnfsexp man page:
The rmnfsexp command removes an entry from the exports list for NFS clients. The rmnfsexp command
starts the exportfs command to unexport the specified directory. If an entry exists in the
/etc/exports file, that entry is removed.
{noformat}
Unfortunately these commands do not exist on Solaris. So the question was: How to do this on Solaris?
One solution is to rewrite the parts of the script that uses these commands. The disadvantage of this method is that you're changing a working script and you must test it again after implementing your changes to make sure it still works the way it worked before.
Another solution is to create the commands mknfsexp and rmnfsexp on Solaris (either as scripts or binaries). But doing it this way you must ensure, that these new commands exist on every Sun machine on which your script should run.
A much better solution is to define the missing functions in the script itself. This way you don't need to change the logic of the existing script and you do not have to take care to copy additional scripts/binaries to the machine running Solaris on which your script should run. But you must make sure, that your new function is only called on Solaris (and not on AIX where these functions are not needed) and therefor we use a conditional definition:
{code}
# define functions missing in Solaris
#
# get the current OS
#
OS="$( uname -ns)"
#
#
[ "${OS}"x = "SunOS"x ] && function mknfsexp {
typeset DIR_TO_EXPORT="" CLIENTS=
while [ "$1"x != ""x ] ; do
case $1 in
-d ) DIR_TO_EXPORT=$2; shift ;;
-r ) CLIENTS="$( echo $2 | tr "," ":" )"; shift ;;
esac
shift
done
if [ "${DIR_TO_EXPORT}"x != ""x -a "${CLIENTS}"x != ""x ] ; then
# check /etc/dfs/dfstab
typeset SHARE_COMMAND="share -F nfs -o anon=0,rw=${CLIENTS} ${DIR_TO_EXPORT}"
grep -v "^#" ${DFS_TAB_FILE} | egrep " ${DIR_TO_EXPORT} | ${DIR_TO_EXPORT}$" >/dev/null || echo ${SHARE_COMMAND} >>${DFS_TAB_FILE}
showmount -e | grep "^${DIR_TO_EXPORT} " >/dev/null || ${SHARE_COMMAND} || CheckRC 3 "Warning" "Warning: Error sharing the directory \"${DIR_TO_EXPORT}\" \n\n"
fi
}
#
# rmnfsexp -d "$to_delete"
#
[ "${OS}"x = "SunOS"x ] && function rmnfsexp {
typeset DIR_TO_EXPORT=""
while [ "$1"x != ""x ] ; do
case $1 in
-d ) DIR_TO_EXPORT=$2; shift ;;
esac
shift
done
if [ "${DIR_TO_EXPORT}"x != ""x ] ; then
# delete the share
showmount -e | grep "^${DIR_TO_EXPORT} " >/dev/null && unshare ${DIR_TO_EXPORT} || \
CheckRC 3 "Warning" "Warning: Error unsharing the directory \"${DIR_TO_EXPORT}\" \n\n"
# check /etc/dfs/dfstab
TMPFILE="/var/tmp/$( basename $0 ).$$"
grep -v "^#" ${DFS_TAB_FILE} | egrep " ${DIR_TO_EXPORT} | ${DIR_TO_EXPORT}$" >/dev/null
if [ $? -eq 0 ] ; then
grep -v "^#" ${DFS_TAB_FILE} | egrep -v " ${DIR_TO_EXPORT} | ${DIR_TO_EXPORT}$" >${TMPFILE}
cp ${DFS_TAB_FILE} ${DFS_TAB_FILE}.$$ || \
CheckRC 4 "ERROR" "Can not create a backup of the /etc/dfstab (Backupfile is \"${DFS_TAB_FILE}.$$\")"
cp ${TMPFILE} ${DFS_TAB_FILE} || \
CheckRC 4 "ERROR" "Can not change /etc/dfstab (Backupfile is \"${DFS_TAB_FILE}.$$\")"
fi
fi
}
# Note: CheckRC is another function defined in the script not shown here.
# here comes the rest of the existing script without any other changes
{code}
As can be seen in the example above you only need to implement the functionality of the missing function that is used in the script. You don't have to care about the other functionality of the emulated command because the function is only used by your script.
This is only one example where conditional function definitions are useful - I'm sure there are many situations where this functionality of ksh is very useful.
{column}
{column:width=25%}
{include: Links for BA Scripts}
{column}
{section}