Command Line Trash Can (Deferred Deletes)

I’m a Mac. I’m also an Ubuntu. I’m even a PC. In each of these, I have a pretty interface that lets me drag and drop just about anything to the Trash. Albeit an old, old feature that hardly ever comes in handy; when it does, it’s priceless. The thing is, I hardly ever use my GUI. Ever. I ride the command line like a drunken cowboy trying to prove something to the carneys. Given I really adore the concept of the GUI Trash deferred delete paradigm, I’ve added it to my command-line recipe book, giving it to me; GUI or not.

Teh Codez

This approach only really works in bash, so I guess you’ll need to start with that.  Sorry, PC.  It works the same if you’re a bash addict like myself, particularly when in OS X since it, literally, uses the same design and location for your deferred files.  This way, if your GUI’n it for the day, you can crack open the trash and see the files you thought you rm’d from the command line.

function rm() {
    if [ ! -d $HOME/.trash ]
        mkdir $HOME/.trash

    for file in "$@"
        /bin/mvbackup=numbered –target-directory=$HOME/.trash "$file"

Yuppers, that’s it. Here’s the run-down if you haven’t figured it out yet:

  • If you don’t already have a “.trash” directory in your home directory, it will create one for you.
    • OS X uses “.Trash”, but also has transparent casing rules for directories which ensures your files will end up in the correct directory.
  • For each of the files you want to remove:
    • Will move them from the working location into your new “.trash” directory with a slightly modified file name:
      • Prefixed with the current Unix time stamp.
      • Forward slashes removed and replaced with underscores.
        • Directories will be included in this, giving only one level to your “.trash” bin, the directories named appropriately.
    • This will let you remove multiple files of the same name in the same directory and keep each version, stamped with the time of removal.

Deferring The Delete

With the first part out of the way, the second part is actually committing the delete.  At some point, it makes sense to physically free up the space on your disk with files that are getting too much dust in your deferment directory.  This little cron line can help with that:

0 0 * * * /usr/bin/find /home/trevor/.trash/ -mtime +30 -maxdepth 1 -exec /bin/rm -rf {} \;

Change the mtime to how ever many days you want files to stick around in your directory, but the idea here is: At midnight, every day, we will physically remove any files that are older than 30 days from the deferment queue (“.trash” directory).

You’re welcome.

Update (2010-06-25): Thanks to the commentors here and in other forums, I have slightly updated the rm() function to be a little more forgiving and function more like the standard rm

Tags: , ,


  1. Thanks for the code snippet. I remember seeing something like this done on IBM’s AIX in ‘91 or so. Wonder why it fell into disuse.

    You may want to add some flags to 1) bypass the trashcan funtionality and do an actual delete and maybe 2) some kind of “rm -i” analog.

    Also, you may want to quote $i in case it contains spaces in the filename.

  2. You also want to quote the $*, preferrably as “$@”.

    But why not save files starting with ‘-’?

    And why do you prefer loosing the directory information? A `mkdir -p $(dirname “$i”)` might save you that.

  3. Instead of ’sed’ you can also use bash’s builtin capabilities:

    FOO=”hello world”
    BAR=${FOO/ /_}
    echo $BAR

  4. It is a bad idea to use the same names for common functions.

    One day, you will be logged in another server, you’ll perform your ‘rm’ and oups… it was not trashed.

    Much better to give it another name. Worst case that happens when you log in another server, the command is not found.

    • This is very true and something I preach often. What I found with this was after years of assuming `rm` was the end of a file, I now forget that it doesn’t and am just as careful everywhere else. This is case-by-case and a very good point; just what I’ve found.

  5. 1. pretty sure it fell into disuse because it’s slow, especially on servers where /home may well be an NFS share or something. Plus you’re frequently going to just end up filling /home. Obviously this is just as true for desktops, but I don’t find myself deleting a lot of one-off little files on servers.

    2. Largely because your second step (the deferred delete) can be automated with tmpwatch, and in that case it frequently just makes sense to tmpwatch the directory that accumulates the junk in the first place.

  6. Some questions from the Bash impaired…

    1. Where is the value for $* coming from?
    2. Why do you have to use $?
    3. Why $i after first using i and then $?
    4. Why are you searching for files beginning with -?
    5. Does that sed command do a search and replace?

  7. I recently created a Python package that send files to trash natively on OS X/Windows/Linux. You might want to check it out:

  8. Does it work on deleting directories? I am getting an error: sed: 1: “’s///_/g’”: invalid command code ?

    The directory is moved to the trash though.

    Many thanks for this script!

  9. See this bash function for a trash command that’s compatible with the GNOME desktop’s trash.

Leave a comment