Figure 1: Example of Bourne shell with signal handling
#!/bin/sh
#
# Example 1 - Bourne shell with signal handling
#
# This Bourne (or Korn) shell script illustrates the
# use of traps to catch common signals. This script:
# 1 Generates in a file a listing of all files in a
# users' home directory.
# 2 From that file generates a "cull file" listing
# candidates for removal.
# 3 The user can stop at this point, proceed to
# generate a script file containing rm commands,
# or remove the files with interactive confirmation.
#
# If this script is run with an argument, it is taken
# to be a previously generated cull file.
#
# John Lees lees@cps.msu.edu
# Systems Analyst http://web.cps.msu.edu/prip
# Computer Science Dept, Michigan State University
# Pattern Recognition & Image Processing Laboratory
LS_FILE="/tmp/ls.$$"
CULL_FILE="/tmp/cull.$$"
RM_FILE="/tmp/remove.$$"
# Set a trap to remove the temporary files on all
# the usual signals. With the Bourne shell, signal 0
# means normal exit from the shell.
trap "/bin/rm -f $LS_FILE $CULL_FILE $RM_FILE; \
exit 1" 0 1 2 3 15
# Did the user supply a cull file?
if test -z "$1" ; then
# No. Create a file containing a listing of all files
# in the home directory. Use the SVR4 ls command.
echo "Finding all files, please be patient..."
cd
/bin/ls -ablLR `pwd` > $LS_FILE
# Read through the listing looking for files that could
# be removed. Create a cull file having these entries.
# A simple inline awk program is between the pair of
# single quote ('') characters.
echo "Creating cull list."
/bin/awk ' # This is the beginning of the awk program.
# Matching ":" means this is a new directory.
$1 ~ /:$/ {
dir = $1
}
# Not a blank line and not the "total nnn" line.
# The last token on the line is the filename.
NF > 0 && NF != 2 {
flag = ""
# This list could be much longer, of course.
if ( $NF ~ /\.bak$/ ) flag = 1
if ( $NF ~ /\.old$/ ) flag = 1
if ( $NF ~ /~$/ ) flag = 1
if ( flag == 1 ) {
# Print the directory just once.
if ( dir != prev ) {
print dir
prev = dir
}
# Print the file.
print $0
}
} # End of the awk program.
' dir="`pwd`:" $LS_FILE > $CULL_FILE
else
# The user has supplied a cull file. Reset the trap
# so it is not removed.
trap "/bin/rm -f $RM_FILE; exit 1" 0 1 2 3 15
CULL_FILE=$1
fi
# The cull file looks like an "ls -lR" listing of only the
# files to possibly remove. Ask the user what to do next.
DONE=""
WHAT=""
while test -z "$DONE" ; do
echo " "
echo " 1 Quit, leaving the cull file $CULL_FILE."
echo " 2 Create a script file you can run to do the\c"
echo " removals later."
echo " 3 Interactively remove the files now."
echo " 4 List the cull file, then return to this menu."
echo "(Ctrl-C to quit, doing nothing.)"
echo "Enter number of choice (1-4): \c"
read CHOICE
DONE="done"
case $CHOICE in
1) trap "/bin/rm -f $LS_FILE; exit 1" 0 1 3 15
echo "The file listing possible files to \c"
echo "remove is \"$CULL_FILE\"."
echo "You can rerun $0\c"
echo "using that file as the argument."
exit
;;
2) WHAT="script"
;;
3) WHAT="interactive"
;;
4) DONE=""
${PAGER:-/usr/bin/more} $CULL_FILE
;;
*) DONE=""
;;
esac
done
#----------
# Choice 2
#----------
if test "$CHOICE" = 2 ; then
# Read the cull file and build a file of rm commands.
echo '#!/bin/sh' > $RM_FILE
echo "# \c" >> $RM_FILE
echo "`/usr/bin/date`" >> $RM_FILE
/bin/awk '
$1 ~ /:$/ { # Directory.
dir = substr($1, 1, length($1) - 1)
}
NF > 2 { # File.
print "/bin/rm -f " dir "/" $NF
}
' dir="$HOME" $CULL_FILE >> $RM_FILE
# Make the kill file executable, change the trap so the
# remove file is not removed.
/bin/chmod 700 $RM_FILE
if test -z "$1" ; then
trap "/bin/rm -f $LS_FILE $CULL_FILE; \
exit 1" 0 1 2 3 15
else
trap "/bin/rm -f $LS_FILE; exit 1" 0 1 2 3 15
fi
echo "The file containing rm commands is $RM_FILE."
exit
fi # End of choice 2
#----------
# Choice 3
#----------
# Interactive removal.
# Save the terminal stdin as file descriptor 3 for use in
# user interaction. Attach stdin (descriptor 0) to the cull
# file.
exec 3<&0 <"$CULL_FILE"
# From this point on in case the user panics and hits
# Control-C we want to give her the option to continue.
# The trap to remove all /tmp files on the other signals
# is still in effect.
# The Control-C handler. This function must appear before
# the trap statement that references catch_c.
catch_c() {
# Read from the terminal using descriptor 3.
echo "Do you really want to quit? \c"
read ANSWER <&3
if test "$ANSWER" = "y" -o "$ANSWER" = "Y"
then
echo "Bye. /tmp files removed."
exit 1
else
echo "Continuing..."
fi
} # end of catch_c
# Set a trap to catch Control-C. The previous traps set on
# signals 0, 1, 3, and 15 remain in effect.
trap "catch_c" 2
# Read the cull file. As each file is encountered, ask the
# user for confirmation and then remove the file or not.
# The read uses descriptor 0, attached to the cull file.
DIR=$HOME
while read FIRST REST
do
# First character of first token.
C=`echo "$FIRST" | sed -e 's/^\(.\).*$/\1/'`
# Directory name.
if test "$C" = "/"
then # Directory
DIR=`echo "$FIRST" | sed -e 's/://'`
continue
fi
# File name.
if test "$C" = "-"
then # File
FILE=`echo "$REST" | sed -e 's/^.* \([^ ]*\)$/\1/'`
echo "Remove $DIR/$FILE? \c"
# Read from terminal using descriptor 3.
read REPLY <&3
if test "$REPLY" = "y" -o "$REPLY" = "Y"
then
/bin/rm -f "$DIR/$FILE"
fi
continue
fi
done
# Done with the interactive removal.
exit
|