Stop Using `rm` in Bash. Use `del`

35 points by raibosome ↗ HN
We’ve all had our fair share of accidentally removing files. Instead of

  rm my_file.txt
or

  rm -rf my_folder
we do

  del my_file.txt
or

  del my_folder
where you can define your Bash alias for `del` in ~/.custom_aliases as

  function del() {
      mv $* ~/.Trash
  }
which simply moves your files/folders to the trash such that you can recover them easily later.

What’s your alternative?

75 comments

[ 15.0 ms ] story [ 2085 ms ] thread
I wish something like this were built into kernel filesystem driver. All deletions automatically go to this specific place in the filesystem.
This would be fun as an experiment to see how quickly it fills up the drive, but probably utterly useless in production. A lot of stuff is creating and deleting files all the time, e.g. logrotate.
It could be fifo and you would still be able to undo damage for some time.
I would hate that behavior, so if it's brought into Linux at the driver level (which I think is an inappropriate place for it -- the shell is the right place), it should be optional.
For Linux users: also look into the trash-cli [1] package, which complies with the FreeDesktop.org trash specification and remembers the original path, etc. so that trash items can be restored even with filename collisions. Then it's

    trash-put my_file.txt
[1] https://github.com/andreafrancia/trash-cli
Until at least an year ago, the Ubuntu version (and likely, the upstream on), wouldn't work on certain filesystems.

I'm not sure about the current state, but one needs to test is very carefully before using it.

While not an alternative, please bugfix your bash:

mv "$@" ~/.Trash/

https://github.com/koalaman/shellcheck/wiki/SC2086

Even simpler:

  alias del="mv -t ~/.Trash/"
Now let's delete them after roughtly 30 days:

  alias del="mv -t ~/.Trash/ ; find ~/.Trash/ -mtime +30 -exec rm {} \;"
This is not fine, as deleting a small file can be very long if there's a large file to be deleted in the trash.
Yeah running the delete in the user's crontab (i.e. in the background and on a schedule) would be a better option IMO.
This fails on directories, as the -r switch was not included:

    mkdir foo; del foo
and including it will spawn file not found errors for the contents of the foo directory, if any.

EDIT: See also neighbor comment about appending filenames!

This does not work. The arguments to `del` get appended at the end, after `find`. You want this:

  del() { mv "$@" ~/.Trash/ && find ~/.Trash -mtime +30 -delete }
I also replaced the unnecessary exec by find's builtin -delete
Thank you, it's painful to see people providing replacements for critical commands like `rm` without understanding basic shell features like aliases.

And just a reminder everybody please don't run random scripts you find on the internet.

P.S. you need a semicolon before the close brace :)

Correct me if I'm wrong, but wouldn't that instantly delete all moved files which are older than 30 days since mv keeps the mtime?
This fails on non-GNU mv(1) binaries such as macOS.
Thanks for pointing out! Now everyone’s Bashing me in their comments.
rm is for removing stuff. If you don’t want to remove the file, use mv.

Take care when entering commands, if it’s important that you don’t mess up, spend an extra second. Don’t run around shooting rm -rf as super user.

With great powers comes great responsibility.

Would be nice if filesystems were garbage collected, though. I don't see a fundamental reason why rm couldn't be undoable the second after you issue it.
Most have SSD drives now that trims the space on delete. Not sure how easy it is to mark regions on the SSD for "undelete" when it has been trimmed. In some cases the deleted region of the drive may even be mapped to another place on the memory chip itself to cycle it.
On Linux at least, it's not recommend to run continuous TRIM (aka "discard"). Instead, you can run fstrim on a timer to clean things up periodically. Most SSD's can actually do either, but discard is recommend against for NVMe drives, and many SSD's have bugs, so overall periodic trim is the way to go.
Check out nilfs, where this is explicit. Every filesystem action results in a checkpoint, and checkpoints are garbage collected only as-needed to maintain free space.
I've never liked the idea of a trashcan, and usually shift-delete when I'm in the gui. Deleting shouldn't be done casually, but a ui shouldn't second guess a user any more than it has to.
I habitually shift+delete too, but I won't say I've never made a mistake.

It's much less hazardous doing this when everything is in source control, though. :)

This fails in the GUI in cases such as if you accidentally hit navigation keys close to the Del key, like Home, End, etc. In those cases you may accidentally change the file selection in the same movement as the deletion, and then you whack the wrong file.

If you’re the person in charge of making the delete operation the best and safest it can be, you do not have the luxury of yelling at users to just be more careful, because the data shows very plainly that doesn’t work (despite this being the approach most IT people seem to think is acceptable). In this role, with these constraints, the inevitable conclusion is the make a trash can.

This is going to cause you pain if the tree you're "deleting" is on a different filesystem to ~ and too big...
Time Machine.
For the unaware, Time Machine is the macOS built-in backup system. Once configured, it takes frequent filesystem snapshots and syncs them to a connected storage device. If the file being removed is included by those backups, and existed long enough to be in a snapshot, then you can restore it from the TM backup. Neither of those criteria are guaranteed, as when working with files in a Terminal or bash script you can easily create and remove files with names and/or locations that exempt them.
I move to /tmp and it gets deleted on next reboot.
/tmp is a ramdisk on some systems, which makes this particular approach a very risky endeavor to use as a global replacement for ‘rm’ as the OP suggests.
Sure, also it works for me because it is on a system that is frequently turned off. If it would have to stay on for a long time it would fill /tmp with garbage.
I meant to warn others that, for example, “del foo.iso” could fail due to OOM. As long as they understand that, your use case will work fine for them.
This is another example that shows that Bash (and similar shells) should not be used for scripting.

It's great for the command line, but for scripting there are much better, cleaner, faster and safer alternatives.

Like what? Sh? Zsh?
Please elaborate :)
There's plenty of good reasons not to use shellscript, but someone not knowing the difference between "$@" and $* isn't one of them. This is prominently documented in Bash's documentation: https://www.gnu.org/software/bash/manual/html_node/Special-P...
Nothing about that is especially prominent (its just regular documentation), and then you still need to consider how any given utility will interact with one word vs multiple words.
What? No, come on. You can’t extrapolate “someone didn’t read the manual” to “don’t use shell scripting”.
Or use a snapshotting filesystem, so you can simply go back in time if you mess up.
I use borg backup running via cron multiple passes per day. When needed you can mount any backup as a file system for easy restoration. Yes, short-lived files can't be recovered, but that's something I am willing to live with.
If you spend most of your time in emacs, and like to delete/move files in dired, you can use

(setq delete-by-moving-to-trash t)

to achieve the same effect.

This was one of the first things I realized I had to do back when I installed a Red Hat 3.0 for the first time.

My alias was for rm itself. I replaced it completely, as the habit of using rm is hard to forget. Today I don’t use an alias anymore.

I have backups..
Either your backups run continuously on every inode change (see nilfs elsethread), or there’s a window of risk where you create a file and then remove it before your backups run.
nilfs2 is my alternative. It's a log-based filesystem that results in continuous checkpoints that can be upgraded to mountable snapshots at any time. Realized you blew away a file you needed? Made large modifications you wish you hadn't? Just find an earlier checkpoint and your good to go.

Backups too. Nothing replaces backups.

(comment deleted)
How do you manage your ".Trash" folder? Who is in charge of deleting it's content? Do you do it periodically or based on some other event?
My “alternative” to rm is to use mv directly. I just mv files aside whenever I am not 100% confident they are safe/ready to delete permanently.

Personally I’m not a fan of shell environment customizations like this because they are often fragile and may vary between systems. I like to know exactly what commands I’m executing.

> Personally I’m not a fan of shell environment customizations like this because they are often fragile and may vary between systems.

True. I gave up the practice entirely many years ago for a slightly different reason -- I need to use many different systems on a regular basis, and don't want to get used to using something custom that won't exist on random system X without customizing it, too.

Often, I prefer predictability and stability over convenience.

My alternative is to think carefully before hitting return. As a bonus, this works for other commands, too.

Also, '\rm', as many distributions insist on aliasing 'rm' by default.

Or “How I Filled Up /home By ‘Deleting’ A Larger Amount Of Data From A Larger Volume”
As pointed out, the alias should be

  function del() {
    mv “$@“ ~/.Trash
  }
instead. Thanks @floatingatoll!
And if you copy and paste that version, it won't work either.

Also, be aware this will silently delete older files with name collisions.

I've used a tool called 'trash' on OSX for a few years:

`brew install trash`

I dislike the trash bin enough that I intentionally disable it, so personally, I'm perfectly happy with using rm.