May 1996
This is a shell script for Bash, called ‘rm_secure’. I use it as frontal for the rm command. It stores the deleted files in an archive in the user’s directory. A command-line option allows the user to view the content of this archive, and another option permits the restoration of the deleted files.
For example :
$ ls -l -rw-r--r-- 1 ccb users 22 May 26 10:33 important_file -rw-r--r-- 1 ccb users 23 May 26 10:34 not_important $ rm * (OOPS!) $ ls -l $ rm --viewtrash -rw-r--r-- 1 ccb users 22 May 26 10:35 1996 important_file -rw-r--r-- 1 ccb users 23 May 26 10:35 1996 not_important $ rm --restore important_file $ ls -l -rw-r--r-- 1 ccb users 22 May 26 10:35 important_file $ rm --viewtrash -rw-r--r-- 1 ccb users 23 May 26 10:35 1996 not_important $ rm --emptytrash $ rm --viewtrash $
Okay, it slows down a few the rm command. But it may also save hours of work lost due to a keystroke error…
There is the script ‘rm_secure’ :
#!/bin/bash
# Configuration
# the real 'rm' command
bin_rm=/bin/rm
# where archiving the files
Archive=~/.rm_saved.tar
# you may prefer something like :
# Archive=/var/trash/$USER/saved_file.tar
# (with write access permission on the directory)
# global variables for the options
Opt_recursive=0
Opt_no_secure=0
Opt_restore=0
Opt_rm=""
# function for archiving a file or a directory
save_file() {
if [ $Opt_no_secure -ne 1 ] ; then
# set date/time of deletion
touch "$1" > /dev/null 2>&1
if [ -f $Archive ] ; then
tar --delete -f "$Archive" "$1" > /dev/null 2>&1
tar -rf "$Archive" "$1" > /dev/null 2>&1
else
tar -cf "$Archive" "$1" > /dev/null 2>&1
# r/w access only for the user
chmod 600 "$Archive"
fi
fi
}
# function for restoring file or directory
restore_file () {
if [ -f $Archive ] ; then
tar -xf "$Archive" "$1" > /dev/null 2>&1
tar --delete -f "$Archive" "$1" > /dev/null 2>&1
fi
}
# reading the command-line args
while getopts "dfirRvns-:" opt ; do
case $opt in
d ) Opt_rm="$Opt_rm -d" ;;
f ) Opt_rm="$Opt_rm -f" ;;
i ) Opt_rm="$Opt_rm -i" ;;
r | R ) Opt_recursive=1
Opt_rm="$Opt_rm -r" ;;
v ) Opt_rm="$Opt_rm -v" ;;
n ) Opt_no_secure=1 ;;
s ) Option_restore=1 ;;
- ) case $OPTARG in
directory ) Opt_rm="$Opt_rm -d" ;;
force ) Opt_rm="$Opt_rm -f" ;;
interactive ) Opt_rm="$Opt_rm -i" ;;
recursive ) Opt_recursive=1
Opt_rm="$Opt_rm -r" ;;
help ) $bin_rm --help
echo "(rm_secure)"
echo " -n, --nosecure delete without backup"
echo " --viewtrash list the saved files"
echo " --emptytrash erase the saved files"
echo " -s, --restore restore the specified files"
exit 0 ;;
version ) $bin_rm --version
echo "(rm_secure 1.0)"
exit 0 ;;
verbose ) Opt_rm="$Opt_rm -v" ;;
viewtrash ) if [ -f $Archive.gz ] ; then
tar -tvzf $Archive.gz
fi
exit 0 ;;
nosecure ) Opt_no_secure=1 ;;
emptytrash ) if [ -f $Archive.gz ] ; then
$bin_rm $Archive.gz
fi
exit 0 ;;
restore ) Opt_restore=1 ;;
* ) ;;
esac ;;
? ) ;;
esac
done
shift $(($OPTIND - 1))
gunzip $Archive.gz >; /dev/null 2>&1
# restoration ?
if [ $Opt_restore -ne 0 ] ; then
while [ -n "$1" ] ; do
restore_file "$1"
shift
done
exit 0
else
while [ -n "$1" ] ; do
if [ -d "$1" ] ; then
# the directories are archived only with
# the -r option
if [ $Opt_recursive -ne 0 ] ; then
save_file "$1"
fi
$bin_rm $Opt_rm $1
elif [ -e "$1" ] ; then
# existing file
save_file "$1"
$bin_rm $Opt_rm $1
else
# let 'rm' give his error message
$bin_rm $1
fi
shift
done
fi
nice gzip $Archive > /dev/null 2>&1 &
# -- end of script --
Place it in /usr/bin or /usr/local/bin then insert a ligne :
alias rm='/usr/local/bin/rm_secure'
in /etc/profile, so this script will be called by Bash in the place of the true rm command.
You can use the ‘–nosecure’ or ‘-n’ option to delete a file without archiving it. This is useful when you decide to erase huge amount of files in recursive directories (for example a package you have tested but find uninteresting).
I use a cron job to deleted the archived files every day (running as root job).
# crontab -l [ …] 00 04 * * * /usr/local/bin/empty_trash #
Here is the ’empty_trash’ script :
#! /bin/bash
for user in /home/* ; do
/bin/rm $user/.rm_saved.tar.gz
done
/bin/rm /root/.rm_saved.tar.gz
# -- end of script --
Maybe you can prefer something like :
trap '/bin/rm ~/.rm_saved.tar.gz EXIT
in /etc/profile, which erase the archive each time the user exits the shell. (I’ve not fully tested this)
Obviously this tips doesn’t secure the deletion of files or directories by a file-manager, but I find it quite usefull, especially when doing administrative jobs as root (‘rm tmp/ *’ in place of ‘rm tmp/*’ …)
2 Réponses
URL de trackback pour cette page
It seems cool but i think there is a mistake on the definition of this variable.
OPTIND is not declared.
shift $(($OPTIND – 1))
OPTINDis a special variable for Bash. Here’s an excerpt of the bash man page :OPTIND The index of the next argument to be processed by the getopts builtin command (see SHELL BUILTIN COMMANDS below). [...] getopts optstring name [args] getopts is used by shell procedures to parse positional parame‐ ters. optstring contains the option characters to be recog‐ nized; if a character is followed by a colon, the option is expected to have an argument, which should be separated from it by white space. The colon and question mark characters may not be used as option characters. Each time it is invoked, getopts places the next option in the shell variable name, initializing name if it does not exist, and the index of the next argument to be processed into the variable OPTIND. OPTIND is initial‐ ized to 1 each time the shell or a shell script is invoked. When an option requires an argument, getopts places that argu‐ ment into the variable OPTARG. The shell does not reset OPTIND automatically; it must be manually reset between multiple calls to getopts within the same shell invocation if a new set of parameters is to be used. When the end of options is encountered, getopts exits with a return value greater than zero. OPTIND is set to the index of the first non-option argument, and name is set to ?. getopts normally parses the positional parameters, but if more arguments are given in args, getopts parses those instead. [...]