180

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.

2
  • 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, 2014 at 13:54
  • Also see askubuntu.com/q/468721/250556 for googlers looking for ubuntu/debian/linux file trashing. Jul 16, 2015 at 19:48

15 Answers 15

124

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.

17
  • 5
    Excellent answer, much better than mine! May 9, 2012 at 15:25
  • 30
    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. May 9, 2012 at 16:39
  • 34
    trash is also available via the brew package manager. just use: brew install trash. Jan 22, 2013 at 23:03
  • 9
    @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, 2013 at 0:36
  • 3
    I was able to fix the error by running brew remove trash and then brew install trash. Jan 16, 2015 at 6:41
152

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

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

6
  • 3
    What an elegant solution!
    – peizhao
    May 18, 2015 at 0:35
  • 6
    Also available in macports: port install trash Jul 19, 2015 at 2:57
  • every time I try to brew install trash, I get this: pastebin.com/N92cM7d8
    – Ky -
    Oct 30, 2015 at 14:32
  • @BenC.R.Leggiero I would take that issue over to github.com/ali-rantakari/trash/issues. Did you brew update first? Works good on my end. Nov 12, 2015 at 19:27
  • @PaulWenzel yes, and it seems to update just fine. I'll post an issue.
    – Ky -
    Nov 12, 2015 at 19:37
32

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

8
  • 6
    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, 2016 at 18:07
  • 3
    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, 2017 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. Sep 6, 2018 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. Sep 10, 2018 at 13:21
  • 3
19

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
  • 2
    Simple, effective, and no need to install anything! Nice.
    – SilverWolf
    Dec 5, 2018 at 4:15
8

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)
}
4
  • 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, 2015 at 5:07
  • @jherran thanks for the reminder, I added a code segment
    – slf
    Mar 20, 2015 at 11:43
  • This is my preferred answer because it uses the same underlying logic and APIs as the GUI. Oct 7, 2015 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. Oct 7, 2015 at 14:18
3

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

3
  • 3
    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" Feb 21, 2014 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, 2015 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, 2016 at 6:09
3

This is an improvement to the answers given by Antony Smith and cde.

The problem with embedding a filename in a string that is passed to osascript via -e is that, on modern Unix-like systems, filenames can contain quotes, to the effect that parts of the filename could be run as AppleScript.

A safer way to do this is to read the filename from an environment variable:

trash() (
    : "${1:?}"
    case $1 in
        (/*) FNAME="$1" ;;
        (*)  FNAME="$(pwd)/$1"
    esac
    export FNAME
    exec osascript <<-EOF >/dev/null
        set fName to system attribute "FNAME"
        tell application "Finder" to delete my (POSIX file fName)
    EOF
)

If you add this function to your .bashrc or .zshrc, you can call trash from the command line. EDIT: Though turning this into a function that is actually useful requires more work, of course.

1
  • Nice. I forgot that hfs + and apfs allow " and other special characters in filename. But if you use quotes in filenames, there's a 8th level of \"hell\".
    – cde
    Mar 8 at 8:51
2

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.

2

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 $$$
1
  • have edited accordingly - thank you for the input!
    – ryantuck
    Aug 30, 2018 at 22:27
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!

4
  • 1
    Don't do it! Installer scripts may use rm and hang with the alias rm -i.
    – Old Pro
    May 9, 2012 at 20:43
  • 3
    @OldPro: .bashrc is only executed if the shell is interactive. Check the man page! May 9, 2012 at 21:07
  • 1
    i would advise against removing safety nets, or admonishing others to do so.
    – Randy L
    Feb 6, 2014 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, 2018 at 14:10
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.

8
  • 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, 2012 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? May 9, 2012 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... May 9, 2012 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 May 9, 2012 at 21:51
  • 3
    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, 2013 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.*
-3

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

trash() {
   mv $1 ~/.Trash
}
3
  • ? why a negative vote? this would be my thought as well.. Aug 1, 2014 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, 2015 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, 2015 at 10:46

You must log in to answer this question.

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