Rm Is Dangerous!

Short post here but I think it’s worth writing about. I use Linux (Ubuntu) for my primary daily operating system and am in the terminal a lot; while running a certain command that I cannot remember, a directory named ~ (tilde) was created and seeing the mistake I promptly typed rm -rf ~ to delete it.

That was a massive mistake. First mistake was using rm -rf on an empty directory - that’s what rmdir is for. My second mistake was a bit more subtle: ~ is an alias for the user’s home directory, in this case, /home/parnell and typing rm -rf ~ basically said “delete everything recursively in /home/parnell”.

It wasn’t until two seconds after issuing the command that I realized my grave mistake and sadly, it had already removed everything.

A solution isn’t to just be more careful and diligent but to also realize that there are protections in place for this precise sort of human-prone mistake: the “trashcan”, aliases, and deletion pauses and prompts. The first two solutions go together: I aliased rm to a small script that mimics its behavior but uses Ubuntu’s trash-put command to move said directories and files into the trashcan (instead of deleting forever). This is appropriate for the home user, but what about sudo / root?

The final solution is more appropriate for sudo. I have five second pauses and a confirmation prompt whenever I issue an rm command against common or important aliases or globs.

Also - backups, that’s the only reason I was able to bounce back from this mistake!

Below is the alias and script I use to override rm behavior with the trashcan, the script was found on Alin Andrei’s Blog.

alias rm="trash-rm"

#!/bin/bash
# filename: trash-rm
shopt -s extglob
recursive=1
declare -a cmd
((i = 0))
for f in "[email protected]"
do
  case "$f" in
    (-*([fiIv])r*([fiIv])|-*([fiIv])R*([fiIv]))
    tmp="${f//[rR]/}"
    if [ -n "$tmp" ]
    then
      #echo "\$tmp == $tmp"
      cmd[$i]="$tmp"
      ((i++))
    fi
  recursive=0 ;;
(--recursive) recursive=0 ;;
(*)
if [ $recursive != 0   -a  -d "$f" ]
then
  echo "skipping directory: $f"
  continue
else
  cmd[$i]="$f"
  ((i++))
fi ;;
esac
done
trash-put "${cmd[@]}"