Update: Creating a TrashCan for shell undelete
update: I updated this script so that it would put a number at the end of the file name if it already exists in the trash… it’s a slow process (increment from 0 and test until you don’t find an existing file) but it works
Original post follows:
so a couple of weeks ago I was up far later than I should have been and managed to run the following, as root, in the root directory /
rm -rf *
What I was trying to do is delete a bunch of backup files that my backup script had been sticking in the wrong location (the smart thing would have been to copy the wrongly placed backup files into the correct place, and also not use -rf, but i’m a noob)
So, as you can imagine, after about 2 seconds (the time it took me to realize what had just happened and instantly wake up) the server was foobared. Now that it’s been a couple weeks I can actually marvel at how fast rm is, it literally deleted almost everything on the server (everything that wasn’t running at least) in a matter of seconds, that’s pretty impressive when you are use to deleting things in windows (and I almost always shift delete, a dangerous pattern emerges…)
Anyway, so I had to re-install the OS and everything else. Luckily I had a 5 day old backup of the web and svn contents, and some chrome caches of my blog (which had all of my instructions for getting the server back up and going) so I wasn’t fully up a creek. After restoring everything I did some searching around and found a way to replace rm with a move to trash bash script which is complemented by a cron that runs to clean out old trash.
Here’s how to get the same thing
edit your .bashrc file and remove your rm alias (if there is one) and add the following two lines:
vim ~/.bashrc
alias rm='/usr/local/bin/del' alias rm.old='/bin/rm -i' alias emptytrash='/usr/local/bin/emptytrash'
rm.old will now work as rm did, however I try to forget it exists lest I do the same thing again!
Now, create the /usr/local/bin/del bash script which will look like the following:
vim /usr/local/bin/del
#!/bin/bash
# Description: Replacement for rm. It moves files to trashbin directories
# which are stored on each mount point. trashbins can be different
# for each mountpoint. All trashbins are logged in TRASHBIN_LOG.
TRASH=.Trash-$USER
TRASHBIN_LOG=~/.trashbins
## this is needed to reset TRASH variable for each argument
TRASH_DIR=$TRASH
## loop through all variables that are not options, and mv each to a trashbin.
while [ ! -z $1 ]; do
if [ ${1:0:1} = "-" ]; then
shift
else
## reset trash variable.
## this is important for deleteing multiple files
TRASH=$TRASH_DIR
## Get the Current mount point
MNT=`df "$1" | grep / | awk '{ for (i=6;i<=NF;i++) { printf " " $i } printf "\n" }'`
MNT=${MNT:1}
## Trash bins may be relocated depending on mount point.
## you may change these to your liking.
## TODO: this should be easier to edit, using variables
if [ "$MNT" = "/" ]; then
TRASH=/tmp/"$TRASH"
elif [ "$MNT" = "/home" ]; then
TRASH=/home/$USER/"$TRASH"
else
TRASH="$MNT"/"$TRASH"
fi
## Test for the TRASH folder
if [ ! -d "$TRASH" ]; then
if mkdir "$TRASH" ; then
chmod u+rw "$TRASH"
echo creating $TRASH
echo writing info to ~/.trashbins
echo $TRASH >> ~/.trashbins
else
echo ERROR: cannot create $TRASH
exit 1;
fi
fi
## Move each file to the trash, after updating time-stamp.
touch "$1"
MOVETO="$TRASH/$1"
MOVETOTWO="$TRASH/$1"
n=0
while [ -e $MOVETOTWO ]; do
let "n++"
MOVETOTWO="$TRASH/$1.$n"
done
mv -v "$1" "$MOVETOTWO"
shift
fi
done
chmod 755 /usr/local/bin/del
I also created an emptytrash script
vim /usr/local/bin/emptytrash
#!/bin/bash
#
# Empty the contents in directories listed in ~/.trashbins
#
for i in `cat ~/.trashbins`
do
if [ `ls -a1 $i | wc -l ` -gt 2 ] ; then
find "$i" -print -delete
fi
done
chmod 755 /usr/local/bin/emptytrash source ~/.bashrc
Now that you’ve got everything set up, you’ll want to make a crontab that deletes old trash. I picked 7 days as the “old enough to delete” timeframe
/etc/cron.daily/clean_trash.sh
#!/bin/bash
#
# Empty the contents in directories listed in ~/.trashbins
#
for i in `cat ~/.trashbins`
do
if [ `ls -a1 $i | wc -l ` -gt 2 ] ; then
find "$i" -mtime +7 -delete
fi
done
chmod 755 /etc/cron.daily/clean_trash.sh
and there you have it… whenever you rm something it’ll go into trash. you can recover it from there or you can empty the trash whenever you want. every day things that are 7 days or older in your trash folder will be deleted. and you can always run emptytrash whenever you want and it’ll wipe the trash clean