Bennyland this server is running in my bedroom – benny’s learning how to run a linux server

13Feb/100

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 :)

Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

Connect with Facebook

(required)

No trackbacks yet.