Hack 8 Create a Trash Directory 
Save
"deleted" files until
you're really ready to send them to the bit
bucket.
One
of the first things
Unix users learn is that deleted files are really, really gone. This
is especially true at the command line where there
isn't any Windows-style recycling bin to rummage
through should you have a change of heart regarding the fate of a
removed file. It's off to the backups! (You do have
backups, don't you?)
Fortunately, it is very simple to hack a small script that will send
removed files to a custom trash directory. If you've
never written a script before, this is an excellent exercise in how
easy and useful scripting can be.
1.9.1 Shell Scripting for the Impatient
Since a script is an executable file, you should place your scripts
in a directory that is in your path. Remember, your path is just a
list of directories where the shell will look for commands if you
don't give them full pathnames. To see your path:
% echo $PATH
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/
local/bin:/usr/X11R6/bin:/home/dru/bin
In this output, the shell will look for executables in the
bin subdirectory of
dru's home directory. However, it
won't look for executables placed directly in my
home directory, or /home/dru. Since
bin isn't created by default, I
should do that first:
% cd
% mkdir bin
As I create scripts, I'll store them in
/home/dru/bin, since I don't
have permission to store them anywhere else. Fortunately, no one else
has permission to store them in my bin
directory, so it's a good match.
The scripts themselves contain at least three lines:
#!/bin/sh
# a comment explaining what the script does
the command to be executed
The first line indicates the type of script by specifying the program
to use to execute the script. I've chosen to use a
Bourne script because that shell is available on all Unix systems.
Your script should also have comments, which start with the
# character. It's surprising how
forgetful you can be six months down the road, especially if you
create a lot of scripts. For this reason, you should also give the
script a name that reminds you of what it does.
The third and subsequent lines contain the meat of the script: the
actual command(s) to execute. This can range from a simple one-liner
to a more complex set of commands, variables, and conditions.
Fortunately, we can make a trash script in a simple one-liner.
1.9.2 The Code
Let's start with this variant, which I found as the
result of a Google search:
% more ~/bin/trash
#!/bin/sh
# script to send removed files to trash directory
mv $1 ~/.trash/
You should recognize the path to the Bourne shell, the comment, and
the mv command. Let's take a look
at that $1. This is known as a
positional parameter and specifically refers
to the first parameter of the trash command. Since
the mv commands takes filenames as parameters, the
command:
mv $1 ~/.trash/
is really saying, mv the first filename, whatever
it happens to be, to a directory called .trash
in the user's home directory (represented by the
shell shortcut of ~). This move operation is our
custom "recycle."
Before this script can do anything, it must be set as executable:
% chmod +x ~/bin/trash
And I must create that trash directory for it to use:
% mkdir ~/.trash
Note that I've chosen to create a hidden trash
directory; any file or directory that begins with the
. character is hidden from normal listings. This
really only reduces clutter, though, as you can see these files by
passing the -a switch to ls. If
you also include the F switch, directory names
will end with a /:
% ls -aF ~
.cshrc .history .trash/
bin/ images/ myfile
1.9.3 Replacing rm with ~/bin/trash
Now comes the neat part of the hack. I want this script to kick in
every time I use rm. Since it is the shell that
executes commands, I simply need to make my shell use the
trash command instead. I do that by adding this
line to
~/.cshrc:
alias rm trash
That line basically says: when I type rm, execute
trash instead. It doesn't matter
which directory I am in. As long as I stay in my shell, it will
mv any files I try to rm to my
hidden trash directory.
1.9.4 Running the Code Safely
Whenever you create a script, always test it first.
I'll start by telling my shell to reread its
configuration file:
% source ~/.cshrc
Then, I'll make some test files to remove:
% cd
% mkdir test
% cd test
% touch test1
% rm test1
% ls ~/.trash
test1
Looks like the script is working. However, it has a flaw. Have you
spotted it yet? If not, try this:
% touch a aa aaa aaaa
% rm a*
% ls ~/.trash
test1 a
% ls test
aa aaa aaaa
What happened here? I passed the shell more than one parameter. The
a* was expanded to a,
aa, aaa, and
aaaa before
trash could execute. Those four parameters were
then passed on to the mv command in my script.
However, trash passes only the first parameter to
the mv command, ignoring the remaining parameters.
Fortunately, they weren't removed, but the script
still didn't achieve what I wanted.
You can actually have up to nine parameters, named
$1 to $9. However, our goal is
to catch all parameters, regardless of the amount. To do that, we use
$@:
mv $@ ~/.trash/
Make that change to your script, then test it by removing multiple
files. You should now have a script that works every time.
1.9.5 Taking Out the Trash
You should occasionally go through your trash directory and really
remove the files you no longer want. If you're
really on your toes you may be thinking, "But how do
I empty the trash directory?" If you do this:
% rm ~/.trash/*
your trash directory won't lose any files! This time
you really do want to use rm, not
trash. To tell your shell to use the real
rm command, simply put a \ in
front of it like so:
% \rm /trash/*
Voila, empty recycling bin.
1.9.6 Hacking the Hack
One obvious extension is to keep versioned backups. Use the
date command to find the time of deletion and
append that to the name of the file in the trash
command. You could get infinitely more complicated by storing a
limited number of versions or deleting all versions older than a week
or a month. Of course, you could also keep your important files under
version control and leave the complexity to someone
else!
|