September 29, 2006

HowTo: trash a file

Filed under: tech — SiKing @ 2:27 pm

Have you ever deleted a file under UNIX only to change your mind in the next instant and immediately started looking for the Recycle Bin? You might have discovered that UNIX does not have one! This is what I did today for the umpteenth time, and here is what I did about it.

This is what I do when I am bored, and when I am bored I tell the whole world about it on my blog.

The code

Place the following code into your .bashrc (.bash_profile, .profile, or whatever else it is you are using). Sorry, but this works only in one of the Bourne shells.

########## TRASHCAN ##########
_today=$(date '+%Y%m%d')
_lastweek=$(( ${_today} - 7 ))
export TRASHCAN=~/.Trash/${_today}/$(date '+%H%M%S')
mkdir -p $TRASHCAN
del () { mv -f $@ ${TRASHCAN}; printf "Dumped into ${TRASHCAN}\n"; }
for _token in `ls ~/.Trash/`
    if [[ "$_token" < "$_lastweek" ]]
        rm -rf ~/.Trash/$_token
unset _today _lastweek _token

If you are one of those people that do not care how things work, as long as they do, then you can stop reading now.

The walk-through

In the first line, we find today’s date; it ends up being an eight-digit number, with a non-leading zero – this is important and explained along with the next line of code.

The second line, performs some arithmetic – shell does this with the $((...)) construct – to figure out the date seven days ago. If the previous line had generated only a two-digit year, with using %y instead of %Y (note the capitalization), then the date would have started with a leading zero this particular decade. Any number in bash, and many other languages as well, that starts with a leading zero is assumed to be in octal format. This means that any digits above 7 are illegal, and in this line bash would have complained vehemently. Isn’t that great?!?!

Onwards to line three. On this line we define a variable TRASHCAN, that will be the path to “today’s Recycle Bin”. You can redefine this variable to any path you like. I personally felt that this will allow me to erase the same file (that I pulled from say CVS) several times, without overwriting (almost) any of the previous. I also chose to use a hidden directory, namely .Trash, in your home directory. Read on, and then decide for yourself if this is the way to go.

Then we actually create the Recycle Bin. The mkdir -p will create the entire path, including all pieces; otherwise the shell will complain, if any of the pieces (except for the last one) are missing.

Next we create our del command. This whole exercise depends on you getting into the habit of deleting stuff with del, rather than with the usual rm. I strongly encourage you to not alias or redefine the rm command, as you will probably break many ‘a script that depend on it! Several things worth commenting here. The mv -f means that it will not warn you if it overwrites a previous file in the Recycle Bin. The $@ means all arguments that you give this command; it will take even wildcards and entire directories, although by the time this command sees it any wildcards will have been expanded. Lastly, it tells you where it has dumped your file; the printf is a better choice over echo, since printf is a builtin and echo is not – builtins are faster, BTW. Also, this must be defined as a function and not an alias. If it were defined as an alias, bash would expand the $@ for you at define-time rather than at run-time – there is a way to do it as an alias, but the syntax is friggin’ nasty, and on a Friday afternoon … not likely.

One other comment worth mentioning here. I also have in my .bashrc the following definition: 'lose () { find . -name *${1}* -print 2> /dev/null; }'. This will find any file, or even portion of a file, you tell it, starting from the current directory. In case you’re wondering about the name “lose”, well ask yourself: what is the opposite of find?

Next we cleanup the Recycle Bin. The for loop will iterate over each entry in .Trash. The entries have to be passed through an ls, as opposed to simply expanded, because in the following test we will be comparing just the entries themselves without the complete path; expansion would have generated the path as well. An alternative could have been to use basename, but not all installations come with this.

The test inside the for loop compares each of the entries against the date last week. Note that the condition uses string comparison and not arithmetic comparison. This means, that majority (but not all!) of things that you place yourself in the Recycle Bin (for whatever reason) will be left untouched. If the comparison passes, the entry is older than the date last week, and it is removed permanently.

Lastly, variables that are not needed outside of this code-snippet are cleaned up.


Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at

%d bloggers like this: