EXAMPLE KORN SHELL SCRIPTS
The knl script is the Korn shell version of the UNIX nl command. It displays line-numbered output.
#!/bin/ksh
#
# knl - Korn Shell line-numbering filter
# A Olczak - ASP, Inc
#
# Initialize line number counter
integer LNUM=1
# Check usage
(($# == 0)) && { print "Usage: $0 file" ;exit 1 ; }
# Process each file
for FILE
do
# Make sure file exists
[[ ! -f $FILE ]] && { print no $FILE; exit 1; }
# Open file for reading
exec 0<$FILE
# Read each line, display with line number
while read -r LINE
do
print "$LNUM: $LINE"
((LNUM+=1))
done
# Reset line number counter
LNUM=1
done
The kcal script implements a menu-driven calendar program. It supports addition, deletion, modification, and listing of calendar entries. It also provides the ability to find the calendar entry for the current day and list all calendar entries.
#!/bin/ksh
#
# kcal - Korn Shell calendar program
#
# Anatole Olczak - ASP, Inc
#
# Process errors
function error {
print ${1:-"unexplained error encountered"}
exit ${2}
}
# Check arguments
if (($# > 0))
then
error "Usage: $0" 1
fi
# Use environment variable setting or default
: ${CALFILE:=$HOME/.calfile}
# Create calendar file if non-existent; flag
# creation error
if [[ ! -f $CALFILE ]]
then
print "Creating default $HOME/.calfile"
> $HOME/.calfile || error "$HOME/.calfile: \
cannot create" 1
fi
# Variable declaration/assignment
typeset DATE= LINE= ENTRY= REPLY="yes" \
PAGER=$(whence more) CLEAR=$(whence clear)
# Set trap to not allow interrupts
trap '$CLEAR; print "\aInterrupt ignored - use \
menu to quit. Press <Return> to continue."; \
read TMP; $CLEAR' INT QUIT
# Set EXIT trap - perform cleanup
trap 'rm -rf /tmp/.FOUND$$ /tmp/.CHANGE$$ \
/tmp/.DEL$$' EXIT
# Check the date
function checkdate {
while ((1))
do
# Prompt for date
read DATE?"Enter date in mmdd[yy] format (default today):"
case $DATE in
# Default - use todays date
"" ) DATE=$(date +%m-%d-%y)
break ;;
# Check the given date
+([0-9]) )
case ${#DATE} in
4|6)
# Set month to 1st 2 chars
typeset -L2 MO=$DATE
# Check length for year;
# 4 = mmdd, 6 = mmddyy
if ((${#DATE} == 6))
then
# Set TMP to get date
typeset -L4 TMP=$DATE
# Get day
typeset -R2 DA=$TMP
# Get year
typeset -R2 YR=$DATE
else
# Get day
typeset -R2 DA=$DATE
# Set to current year
YR=$(date +%y)
DATE=$DATE$YR
fi
# Now check values. DA
# must be in range 01-31
if ((DA < 01 || DA > 31))
then
print "$DA: invalid \
day format - try \
again"
continue
fi
# Month must be 01-12
if ((MO < 01 || MO > 12))
then
print "$MO: invalid \
month format - try \
again"
continue
fi
# Set format mm-dd-yy
DATE=$MO-$DA-$YR
break ;;
*) # Invalid format
print "$DATE: invalid \
format - try again" ;;
esac ;;
# Invalid date given
* ) print "$DATE: invalid format - try again" ;;
esac
done
}
# Add new calendar entry
function addentry {
$CLEAR
ENTRY="$DATE"
# For existent entry, just add more data
COUNT=$(grep -c "^$DATE" $CALFILE)
if ((COUNT > 0))
then
changeentry
return
fi
# Prompt for input
print "Enter info for $DATE: (enter <Return> by
itself when finished)"
while ((1))
do
read LINE?"=>"
if [[ -n $LINE ]]
then
ENTRY="$ENTRY,$LINE"
else
break
fi
done
# Append to calendar file
print $ENTRY>>$CALFILE
# Sort the calendar file
sort -o $CALFILE $CALFILE
}
function formatentry {
$CLEAR
typeset IFS="," \
BORDER="*********************************" \
BORDER1="* *" \
FILE=$1
if [[ -s $FILE ]]
then
# Open calendar file for reading, and
# format output
(exec 0<$FILE
while read -r ENTRY
do
print "$BORDER\n$BORDER1"
set $ENTRY
typeset -L35 LINE="DATE: $1"
print "* $LINE*"
shift
print "$BORDER1"
for i
do
LINE="$i"
print "* $LINE*"
done
print "$BORDER1"
done
print "$BORDER"
) | $PAGER
else
print "No entries found."
fi
# Prompt to continue
until [[ $REPLY = "" ]]
do
read REPLY?"Enter <Return> to continue..."
done
}
# Find specific entry
function findentry {
$CLEAR
# Check for entry - put it in temp found file
grep $DATE $CALFILE >/tmp/.FOUND$$
# Format found entries
formatentry /tmp/.FOUND$$
}
# Change an entry
function changeentry {
# Find specific entry - put it in temp found file
grep $DATE $CALFILE | tr ',' '\012'>/tmp/.FOUND$$
# Return if no entry was found
if [[ ! -s /tmp/.FOUND$$ ]]
then
$CLEAR
read TMP?"Entry for $DATE not found - press
<Return> to continue"
return
fi
# Prompt again for change
while [[ $REPLY != "" ]]
do
read REPLY?"Change/Add to entry for <$DATE>?"
case $REPLY in
[yY]* | "" )
break ;;
[nN]* ) print "Ok, aborting entry change"
return ;;
* ) print "Invalid reply - try again." ;;
esac
done
# Edit the temporary found file
${EDITOR:-vi} /tmp/.FOUND$$
# Remove the specified original entry
grep -v $DATE $CALFILE > /tmp/.CHANGE$$
# Put back new change in record format.
# Add trailing \n
(cat /tmp/.FOUND$$ | tr '\012' ',' ; print ) \
>>/tmp/.CHANGE$$
# Put back new file
cat /tmp/.CHANGE$$ > $CALFILE
# Clean up tmp files
rm -rf /tmp/.CHANGE$$ /tmp/.FOUND$$
}
# Remove specific entry
function delentry {
# Look for entry
grep $DATE $CALFILE >/tmp/.FOUND$$
# Return if not found
if [[ ! -s /tmp/.FOUND$$ ]]
then
$CLEAR
read TMP?"Entry for $DATE not found - press
<Return> to continue"
return
fi
# Prompt to delete
while [[ $REPLY != "" ]]
do
read REPLY?"Delete entry for <$DATE>?"
case $REPLY in
[yY]* | "" ) break ;;
[nN]* ) print "ok, aborting delete"; return ;;
* ) print "Invalid reply - try again." ;;
esac
done
# Merge changes - put them in temporary file
grep -v $DATE $CALFILE > /tmp/.DEL$$
# Put back new file
cat /tmp/.DEL$$ > $CALFILE
# Clean up tmp files
rm -rf /tmp/.DEL$$ /tmp/.FOUND$$
}
# Set menu selection prompt
PS3="Enter selection or <Return> for default menu:"
# Display menu
while ((1))
do
$CLEAR
select i in "Add calendar entry" "Delete calendar
entry" "Change calendar entry" "Find calendar entry"
"List all calendar entries" "List todays calendar
entry" "Exit"
do
case $i in
"Add calendar entry")
checkdate
addentry
$CLEAR ;;
"Delete calendar entry")
checkdate
delentry
$CLEAR ;;
"Change calendar entry")
checkdate
changeentry
$CLEAR ;;
"Find calendar entry")
checkdate
findentry
$CLEAR ;;
"List all calendar entries")
formatentry $CALFILE
$CLEAR ;;
"List todays calendar entry")
DATE=$(date +%m-%d-%y)
findentry
$CLEAR ;;
"Exit")
exit ;;
* ) print "\aInvalid selection \c"
read TMP?"- press <Return> to continue"
$CLEAR
continue ;;
esac
done
done
|