129

I do a lot of terminal work, and today had the experience of typing

rm fileInQuestion.txt

Before finding out that I did actually need fileInQuestion.txt. If I'd deleted in the GUI then I would have just gotten it out of the Trash. I'd like to know if it's possible to overload 'rm' in the Terminal in such a way that it sends the file/files to the Trash on the way out.

  • 1
    There are programs that can recover deleted files (as long as those sectors on the hard drive are not overwritten in the mean time!). When this happens, you should use one of those... – iconoclast Jun 6 '14 at 13:54
  • Also see askubuntu.com/q/468721/250556 for googlers looking for ubuntu/debian/linux file trashing. – ThorSummoner Jul 16 '15 at 19:48

14 Answers 14

100

I wouldn't advise aliasing rm to mv as you might get in the habit of rm not permanently deleting files and then run into issues on other computers or under other user accounts when it does permanently delete.

I wrote a set of bash scripts that add more Mac OS X-like command line tools (in addition to a number of the built-in ones like open, pbcopy, pbpaste, etc.), most importantly trash. My version of trash will do all the correct things that aliasing rm won't (and hopefully nothing bad, but I've been using it on my own Macs for a few years now without any lost data), including: renaming the file like Finder does if a file with the same name already exists, putting files in the correct Trash folder on external volumes; it also has some added niceties, like: it attempts to use AppleScript when available so you get the nice trash sound and such (but doesn't require it so you can still use it via SSH when no user is logged in), it can give you Trash size across all volumes.

You can grab my tools-osx suite from my site or the latest and greatest version from the GitHub repository.

There's also a trash command developed by Ali Rantakari, but I haven't tested that one myself.

  • 4
    Excellent answer, much better than mine! – user1256923 May 9 '12 at 15:25
  • 24
    I've used trash by Rantakari for quite a while and can really vouch for it. It is compiled Objective-C and cleverly uses standard filesystem APIs and, should it fail (ie. user doesn't have sufficient rights), it calls Finder to trash the files (effectively prompting for authentication). You can read more info of trash from hasseg.org/blog. – Jari Keinänen May 9 '12 at 16:39
  • 26
    trash is also available via the brew package manager. just use: brew install trash. – Landon Kuhn Jan 22 '13 at 23:03
  • 8
    @landon9720 Good point. And, to clarify for others, the trash command available through Homebrew is Alai Rantakari's (see the brew formula). – morgant Jan 24 '13 at 0:36
  • 3
    I was able to fix the error by running brew remove trash and then brew install trash. – Elias Zamaria Jan 16 '15 at 6:41
99

The trash command line tool can be installed via brew install trash.

It allows you to restore trashed files via command line or the Finder.

21

I have an executable called rem somewhere in my $PATH with the following contents:

EDIT: code below is a revised and improved version in collaboration with Dave Abrahams:

#!/usr/bin/env python
import os
import sys
import subprocess

if len(sys.argv) > 1:
    files = []
    for arg in sys.argv[1:]:
        if os.path.exists(arg):
            p = os.path.abspath(arg).replace('\\', '\\\\').replace('"', '\\"')
            files.append('the POSIX file "' + p + '"')
        else:
            sys.stderr.write(
                "%s: %s: No such file or directory\n" % (sys.argv[0], arg))
    if len(files) > 0:
        cmd = ['osascript', '-e',
               'tell app "Finder" to move {' + ', '.join(files) + '} to trash']
        r = subprocess.call(cmd, stdout=open(os.devnull, 'w'))
        sys.exit(r if len(files) == len(sys.argv[1:]) else 1)
else:
    sys.stderr.write(
        'usage: %s file(s)\n'
        '       move file(s) to Trash\n' % os.path.basename(sys.argv[0]))
    sys.exit(64) # matches what rm does on my system

It behaves in exactly the same way as deleting from the Finder. (See blog post here.)

  • 4
    This should have more points IMO. Because it is AppleScript it uses the actual trash process to move the file to trash, which means it will behave exactly the same. Shame a one-liner was not provided however. – mxcl Mar 2 '16 at 18:07
  • 2
    This answer is an object lesson in how to do things right. It works with shell wildcards and it works through the Finder. It doesn't reinvent any wheels, and it's about as simple as can be. I put it in my ~/bin, named it trash, and it worked the first time—enabling me to trash a whole lot of files way more efficiently than if I had to click on them in Finder windows. Much gratitude. I hope you'll post more answers! – Ben Kovitz Apr 5 '17 at 14:50
  • 3
    This version handles quotes. It changes error handling behavior a bit, which in the version above seems to be not-very-carefully-worked-out (errors to stdout instead of stderr, no exit code) but the error you get from osascript when the file doesn't exist is not beautiful so you might want to tune that part. – Dave Abrahams Sep 6 '18 at 21:46
  • 3
    Nice job. This version incorporates those changes, and also (1) tries to imitate the shell command rm as much as possible in terms of displaying messages when files don't exist, and (2) collates everything into a single osascript call. – Anthony Smith Sep 10 '18 at 13:21
  • 3
4

I found a pretty nice code that can be added at the end of user's batch profile and causes rm to move the files to the trash each time it is run.

nano ~/.bash_profile

#... append at the end
function rm () {
  local path
  for path in "$@"; do
    # ignore any arguments
    if [[ "$path" = -* ]]; then :
    else
      # remove trailing slash
      local mindtrailingslash=${path%/}
      # remove preceding directory path
      local dst=${mindtrailingslash##*/}
      # append the time if necessary
      while [ -e ~/.Trash/"$dst" ]; do
        dst="`expr "$dst" : '\(.*\)\.[^.]*'` `date +%H-%M-%S`.`expr "$dst" : '.*\.\([^.]*\)'`"
      done
      mv "$path" ~/.Trash/"$dst"
    fi
  done
}

source: http://hints.macworld.com/article.php?story=20080224175659423

  • 2
    This is v clever but I still wouldn't recommend this. It's clever because its in the bash profile for the user and so only the user can execute this version of the function by typing it in, scripts that rely on rm will still call the original. But I wouldn't recommend doing this because the user will get used to rm acting in this way when it doesn't on other machines. I'm going to use this but rename the function "trash" – Matt Parkins Feb 21 '14 at 10:06
  • I am using the same function with two changes: ① I corrected a bug in the function that causes any folder to be renamed to the timestamp, if it has been tab-completed to include a trailing slash: This requires the following changes: Replacing the line local dst=${path##*/} with local dst=${mindtrailingslash##*/} and inserting another line just before that one that says local mindtrailingslash=${path%/}. ② I use the name function rr. Like this, it does not interefere with plain rm, but the name is similarly short and fast to type (any other name would do). – mach Apr 7 '15 at 14:56
  • Change the name of rm() to rmt() - This way you can still use the rm command when you want. I think of rmt in my head as remove to trash :D – James111 Jan 29 '16 at 6:09
4

Use the terminal command osascript, the AppleScript interpreter.

osascript -e "tell application \"Finder\" to delete POSIX file \"${PWD}/${InputFile}\""

This tells AppleScript to tell Finder to send the file to trash.

PWD is needed for relative file paths, as AppleScript does not handle that well.

  • 1
    Simple, effective, and no need to install anything! Nice. – SilverWolf Dec 5 '18 at 4:15
2

a modern approach using swift

https://github.com/reklis/recycle

//
// main.swift
// recycle
//
// usage: recycle <files or directories to throw out>
//

import Foundation
import AppKit

var args = NSProcessInfo.processInfo().arguments
args.removeAtIndex(0) // first item in list is the program itself

var w = NSWorkspace.sharedWorkspace()
var fm = NSFileManager.defaultManager()

for arg in args {
    let path = arg.stringByStandardizingPath;
    let file = path.lastPathComponent
    let source = path.stringByDeletingLastPathComponent

    w.performFileOperation(NSWorkspaceRecycleOperation,
        source:source,
        destination: "",
        files: [file],
        tag: nil)
}
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – jherran Mar 20 '15 at 5:07
  • @jherran thanks for the reminder, I added a code segment – slf Mar 20 '15 at 11:43
  • This is my preferred answer because it uses the same underlying logic and APIs as the GUI. – Jason R. Coombs Oct 7 '15 at 14:16
  • 1
    Now if only there were a Python version that avoided the need for a 3MB binary to make one system call. – Jason R. Coombs Oct 7 '15 at 14:18
1

While it is possible to make rm move files to Trash instead of removing them, I would advise against bringing the mindset of the safety net of graphical user interfaces to the UNIX shell. There are many ways to do serious damage using the terminal. The best advise IMHO is to simply think twice before hitting the enter key in a shell window.

If you want rm to remind you that you are about to delete a file consider using the following alias (for /bin/bash put this line in .bashrc in your home directory):

alias rm "rm -i"

This will make rm request confirmation before attempting to remove each file.

If you have TimeMachine running (I hope so!) you can always get your file from backup. This way you can lose at most one hour of work. Which is bad enough, of course. So think again before pressing that enter key!

  • 1
    Don't do it! Installer scripts may use rm and hang with the alias rm -i. – Old Pro May 9 '12 at 20:43
  • 3
    @OldPro: .bashrc is only executed if the shell is interactive. Check the man page! – Mackie Messer May 9 '12 at 21:07
  • i would advise against removing safety nets, or admonishing others to do so. – the0ther Feb 6 '14 at 16:18
  • I'll go against the naysayers and say that I use this trick to great effect, but it definitely should be only done knowing the pitfalls. Two not mentioned are that it trains your brain that rm is safer than it is which will get your in trouble on other systems. Also, if you use -f, -i is completely ignored. That said, this is a good safety net. A better one is to never use rm in favor of an rmi alias (alias rmi="rm -i") or the excellent trash utility. Also, I'll add that everyone should have put [ -f ~/.bashrc ] && source ~/.bashrc in their .bash_profile by now. – mattmc3 Jan 6 '18 at 14:10
1

There are two utilities installable via Homebrew that can accomplish this:

  1. trash

    This is a small command-line program for OS X that moves files or folders to the trash. The USP of this command is that enables to easily restore the files. A command to trash files/folders is no use if you can't restore files/folders after trashing them. From the command's website:

By default, trash asks Finder to move the specified files/folders to the trash instead of calling the system API to do this because of the "put back" feature that only works when trashing files through Finder.


-F

Ask Finder to move the files to the trash, instead of using the system API. This is slower, but it utilizes Finder's UI (e.g. sounds) and ensures that the "put back" feature works.

-l

List items currently in the trash. If this argument is used, no files need to be specified.

-e

Empty the trash. trash asks for confirmation before executing this action. If this argument is used, no files need to be specified.

To install trash run the following in Terminal:

brew install trash.


  1. rmtrash

    A command line tool that move files to the trash. From the command's man page:

This command moves files to the trash rather than removing them totally from the file system. Very useful if you decide you want that file after all...


-u USERNAME

an optional argument. This will move the file to the specified user's trash. Note that you need sufficient privileges to accomplish this.

To install rmtrash run the following in Terminal:

brew install rmtrash.

1

Here's a pretty trivial one-line solution to add to your bash profile. Note that it will overwrite something with the same name in the trash already.

trash() { mv -fv "$@" ~/.Trash/ ; }

Usage:

• ~/Desktop $$$ touch a b c
• ~/Desktop $$$ ls
a b c
• ~/Desktop $$$ trash a b c
a -> /Users/ryan.tuck/.Trash/a
b -> /Users/ryan.tuck/.Trash/b
c -> /Users/ryan.tuck/.Trash/c
• ~/Desktop $$$ ls
• ~/Desktop $$$
  • have edited accordingly - thank you for the input! – Ryan Tuck Aug 30 '18 at 22:27
0

Properly trashing stuff (so that it is definitely recoverable) is trickier than simply a mv to ~/.Trash.

osx-trash might be what you're looking for. (Caveat emptor - I haven't tried it, and cannot vouch for how safe it is.)

0

Check out trash-cli. It works cross-platform, no trash sound, and supports Put Back.

You can install it with (requires Node.js):

$ npm install --global trash-cli

Alternatively, if you don't want to use Node.js, you can install the native binary osx-trash manually.

-1

In your .bashrc (or wherever you keep the parameters for your shell), try adding an alias that changes the behaviour of rm to moving stuff to ~/.Trash, as in:

alias rm='move/to/.Trash'

This alias if far from trivial to implement (at least for me) though, because the use of mv (the prime candidate to use for this job) is

mv file where

so having an alias that puts the 'where' part in front of the file to be moved might be pretty sketchy. I'll look into it an might get more substantial advice.

EDIT: I just tried to add the following to my .bashrc, and it works:

function trash { mv "$@" ~/.Trash ; }

It is much more primitive than other suggestions, but you avoid installing new stuff.

  • 3
    Aliasing rm to anything is dangerous because it may break installer scripts. I learned this the hard way when I aliased rm to rm -i and had installs hang. – Old Pro May 9 '12 at 20:42
  • @Old Pro, that's the alias I use for rm in all my computers, from day 0, and I never had issues because of it. Care to give an example? – user1256923 May 9 '12 at 20:56
  • 3
    @OldPro: .bashrc is only used for interactive shells. If you run ./install.sh a new process is started and the alias will not be active. However, if you run . install.sh your current process will execute the installer and the alias is active. RTFM... – Mackie Messer May 9 '12 at 21:21
  • 3
    Then the installer was running an interactive shell and therefore was seriously broken. One broken installer is hardly enough reason to advise against shell aliases in general. YMMV – Mackie Messer May 9 '12 at 21:51
  • 1
    However, it is good advice to not alias the rm command, as morgant said, because you'll become comfortable with rm not actually removing files and then might accidentally delete something on a system where no such alias has been added. Also, moving a file to the trash is not as simple as just mv {} ~/.Trash. If the file is on a separate volume, for example, this will copy the file to your home directory and delete the original. – Josh May 30 '13 at 21:46
-1

I have simply put this script

#!/bin/bash
application=$(basename "$0")
if [ "$#" == 0 ]; then
    echo "Usage: $application path [paths...]"
    exit 1
fi
trashdir="/Users/${USER}/.Trash"
while (( "$#" )); do
    if [ -e "$1" ]; then
        src=$(basename "$1")
        dst=$src
        while [ -e "$trashdir/$dst" ]; do
            dst=$src+`date +%H-%M-%S`
        done
        mv -f "$1" "$trashdir/$dst"
    else
        echo "$1" does not exist.
    fi
    shift
done

in ~/bin/trash, made it excutable chmod +x ~/bin/trash, and added the following line to ~/.bash_profile

PATH=$PATH:$HOME/bin

Then one can use it as

$ trash broken.js olddir cleanup.*
-2

A simple function could let you trash files by moving them to the user's .Trash folder:

trash() {
   mv $1 ~/.Trash
}
  • ? why a negative vote? this would be my thought as well.. – CousinCocaine Aug 1 '14 at 14:25
  • You probably need $* instead of $1, but then you would end up with the same answer as mv "$@" ~/.Trash. Why people vote it negatively, check the comments from the other answer. – kenorb May 6 '15 at 21:36
  • Be careful with this alias; this works if you only have one partition or drive. If you're working on a second volume or network share, this will actually copy the file to your home directory's trash, which is probably not what you wanted to do! – jmk May 28 '15 at 10:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .