Creating a nondestructive 'rm'
Mark Ikemoto
marki at hpiacla.HP.COM
Sun Nov 6 14:46:51 AEST 1988
Try this. It runs a little too slow for me but maybe you're running on
a faster machine.
( Matt, for the b_on, b_off, u_on, u_off script variables, you'll need to
replace <esc> with the real escape character so the bolding will work
on your HP terminal. I deliberately used <esc> so other people's non-HP
terminals accessing Notes wouldn't get screwed up by the escape chars
when they looked at this script. )
Mark
------------ CUT LINE: Remove this line and everything above it ------------
# Bourne shell script
#######################################################################
#
# @(#) TITLE: Safer rm command
#
#
# DESCRIPTION: See user man page below.
#
# INSTALLATION:
#
# Save this to a file. Change user-defined shell vars after the
# script header to your taste and terminal. Set the permissions on
# this script to 'execute'. Invoke this script with no parameters
# to see the embedded man page.
#
# UPDATE HISTORY:
#
# what date/who type of change
# ---- -------- --------------
# 01/18/88
# Mark Ikemoto >Script created.
#
# 03/03/88
# Mark Ikemoto >Added touch command to give file the current time
# so it isn't cleaned up until it is older than the
# system backup timestamp file.
#
# @(#) 11/05/88
# Mark Ikemoto >Added much more comments.
# >Added pseudo support for the -f option.
# >Isolated HP terminal escape chars into shell vars.
#
#######################################################################
# Shell user-defined functions
#
####################################################################
# Start of main commands
#
#-------------------------------------------------------------------
# USER MUST SET THESE VARIABLES FOR INSTALLATION OF THIS SCRIPT
# USER MUST SET THESE VARIABLES FOR INSTALLATION OF THIS SCRIPT
# USER MUST SET THESE VARIABLES FOR INSTALLATION OF THIS SCRIPT
#
junkdirname="$HOME/.rmfiles" # name of user junk file subdir
rmlogfile="rmlogfile" # list of removed files
# bolding/underlining for error messages and for keywords in the
# man page...
b_on='<esc>&dB' # set bolding on for HP terminal
b_off='<esc>&d@' # set bolding off for HP terminal
u_on='<esc>&dD' # set underlining on for HP terminal
u_off='<esc>&d@' # set underlining off for HP terminal
# For other types of terminals, substitute appropo
# terminal char sequences or just set b_on, b_off,
# u_on, u_off to empty ('').
#-------------------------------------------------------------------
# Initialize some global vars
#
PATH=/bin:/usr/bin:/usr/contrib/bin:/usr/local/bin:/etc:.
TZ=PST8PDT; export TZ # set time zone for invocations of cmds like date, etc.
options=
export options
fname=`basename $0`
cap_fname=`echo $fname | tr "[a-z]" "[A-Z]"` # make filename uppercase
cmdline=$* # used in help-checking later on
# default settings:
overwrite='false' # force overwriting; don't prompt for user verify?
interactive='false' # user wants to verify copy for each source file?
removedir='false' # user wants to remove a subdir? default = no.
#-------------------------------------------------------------------
# Set up some traps for signals. NOTE that any shell variables used
# in the trap routine must have been defined previous to this trap
# declaration.
#
trap "echo $cap_fname: Type $fname -h\<ret\> for help.'; exit 2" \
1 2 3 6 7 15
#-------------------------------------------------------------------
# Grab args from command line
#
set -- `getopt ifrh $*` # check if a valid command line entered
if [ $? -ne 0 ]
then
echo "$b_on $cap_fname: Bad runstring option.$b_off"
echo "$b_on Type $fname -h<ret> for help.$b_off "
exit 2
fi
#-------------------------------------------------------------------
# Parse command args
#
help_wanted=false
while [ $# -gt 0 ]
do
case $1 in
-i) interactive='true';;
-f) ;;
-r) removedir='true';;
-h) help_wanted='true';;
--) shift; break;; # end of options in command line;
# source/target names should remain in runstring
*) echo "$b_on $cap_fname: Bad runstring option.$b_off "
echo "$b_on Type $fname -h<ret> for help.$b_off "
exit 2;;
esac
shift
done
#-------------------------------------------------------------------
# Does user want a help screen?
#
if [ -z "$cmdline" -o "$help_wanted" = 'true' ]
then
more <<!
$b_on NAME$b_off
$cap_fname -- Safer rm command
$b_on SYNOPSIS$b_off
$b_on $fname [-i] [-f] [-r <subdir>] <file> ... $b_off
$b_on $fname -h$b_off
$b_on DESCRIPTION$b_off
A safer rm command. Will "delete" files/subdirs and move
them to a user "junk file" subdirectory. The current junk dir
name being used is $b_on $junkdirname $b_off . This junk dir
name is hardcoded into this script. This script assumes that
the junk dir already exists before calling this script.
The $u_on arguments$u_off are:
$b_on <-i>$b_off will cause $fname to obtain authorization
from the user before removing each source file.
$b_on <-f>$b_off does absolutely nothing and is only accepted
for compatibility with the real rm's runstring
options.
$b_on <-r>$b_off will cause $fname to remove the subdir
specified in the runstring. The subdir tree
structure is moved to the junk file subdir intact
before the source subdir is removed.
$b_on <file> ...$b_off are the names of the files/dirs to delete.
$b_on -h$b_off will cause this help screen to be displayed.
This is the same as typing $fname <ret>
with no parameters.
Files deleted can be unremoved by the user; the unremoval must
be done by hand (sorry). This is because the user might have
removed several files with the same name and the user would have
to go into each file anyway to figure out which is the file that
they want to unremove.
When a file/dir is moved to the junk directory, it is renamed
with a unique filename so that future rm'ing of files with the
same name will not cause files in the junk directory to be
overwritten.
However, if all of the removed files in the junk directory have
unique, non-user-friendly names, then the user will have a heck
of a time trying to figure out which file is the one they want
if they want to restore a file.
So, before files are renamed during the remove process, their
original name and their new unique name will be placed as an entry
in a listing file, $b_on $junkdirname/$rmlogfile $b_off , along
with a prefix, 'f' or 'd', to indicate whether the entry is a
removed file or directory, respectively.
Note that once a file/dir has been unremoved, its entry in the
listing file still exists. The user must remove their entry
from this listing by hand (sorry again).
$b_on WARNING$b_off
This script is not portable because of the use of HP terminal
escape sequences in the man page and error messages. You must
alter script shell vars to make this portable.
$b_on AUTHOR$b_off
HP R&D Lab.
!
exit 0
fi
#
#----------------------------------------------------------------------
# Do the main loop
while [ $# -gt 0 ]
do
if [ "$interactive" = 'true' ]
then
echo "Remove $1? (y/n/a[bort]) \c"
read answer
if [ "$answer" = 'a' ]
then
exit 0
fi
if [ "$answer" != 'y' -a "$answer" != 'Y' ]
then
shift # go on to next source file name
continue
fi
fi
if [ -d "$1" ]
then
if [ $removedir != 'true' ]
then
echo "$b_on $cap_fname: Specified directory removal of $1$b_off "
echo "$b_on but remove-dir option (-r) not specified.$b_off "
echo "$b_on Type $fname -h<ret> for help.$b_off "
shift
continue # bypass this name; go to the next one
fi
# create a subdir inside the junk file subdir in which to
# deposit "removed" subdir file(s)
#
rmname="`expr substr $LOGNAME 1 4``date +%m%d%H%M%S`"
mkdir $junkdirname/$rmname
touch "$junkdirname/$rmname" # give file the current time to aid in
# cleaning up the junk dir using this timestamp
cp -r $1 $junkdirname/$rmname
/bin/rm -r $1
echo "d $1 $rmname" >> $junkdirname/$rmlogfile
else
rmname="`expr substr $LOGNAME 1 4``date +%m%d%H%M%S`"
/bin/mv $1 "$junkdirname/$rmname"
touch "$junkdirname/$rmname" # give file the current time to aid in
# cleaning up the junk dir using this timestamp
if [ $? != 0 ]
then
echo "$b_on $cap_fname: Cannot access file/subdir $1 .$b_off "
echo "$b_on Consult man pages or$b_off "
echo "$b_on type $fname -h<ret> for help.$b_off "
exit 1
fi
echo "f $1 $rmname" >> $junkdirname/$rmlogfile
fi
shift
done
exit 0 # removal complete
#######################################################################
# IMPLEMENTATION NOTES/ENHANCEMENT REMINDERS:
#
# 1. I was giving some consideration into making this a C program so that
# it would run faster. Currently, it is too slow for my tastes.
#
# Note that one problem in making this thing run faster would be in
# timestamping the files uniquely, especially if you are copying/renaming
# several short files all at the same time. The system clock would
# not have enough opportunity to change to a unique set of digits.
#
# 2. Instead of uniquely identifying duplicately-named removed files via
# timestamping in the filename, how about keeping the names the same
# as the originals as much as possible but adding number suffixes if
# removing duplicately-named files. This eliminates the need for
# an rmlogfile to map timestamped names to real names.
#
# 3. We give the removed files the current mod timestamp so the files'
# mod timestamp could be used by some sort of cleanup script to do
# periodic cleanup of the junk dir. Maybe the cleanup script could
# be run during login.
#
# 4. If I had more time, I could develop an 'unrm' command script that,
# when invoked with the name of the file/dir to unremove, would
# look in the removed-file listing and display all entries matching
# the user-specified filename. We could provide unique sequence
# numbers for each entry, so that the user, after seeing the display
# of candidate entries, could specify the index number of the
# entry to unremove.
#
# This script would remove the entry from the listing after
# after completion of the removal of the file/dir itself.
#
# The other problem that must be overcome is that even if we display
# the candidate list entries to the user for unremoval, the user still
# may not be able to tell which file is which if there are several
# entries with the same original file name. The fix for this would
# be to allow the user during rm'ing to specify a comment to be added
# to the list file entry for that file. When the user asks to
# unremove a file and is shown the list entries of possible candidates,
# the user will also see the comment field for each entry.
#
More information about the Comp.unix.questions
mailing list