Previous Table of Contents Next


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


Previous Table of Contents Next
1