28

Intention:

rm -rf string*

Problem:

rm -rf string *

The first case is a legitimate and common use of rm, a small typo can cause a lot of problems in the second case. Is there a simple way to smartly protect against an accidental trailing or leading wildcard?

smci
  • 264
bobdole
  • 291

11 Answers11

46

There is no way to a totally bulletproof a system. And adding "Are you sure?" prompts to things is both counterproductive and leads to "Of course I'm sure." kneejerk reactions.

A trick I picked up from a book in years past is to first do ls -R blah* then, do rm -fr blah* if and only if the listing that ls turned up hit what I wanted hit.

It's easy enough to do the ls command first, then , delete the ls -R and replace with rm -fr.

The final question is, "If the information was valuable to you, where's your backup?"

Oliver Salzburg
  • 89,072
  • 65
  • 269
  • 311
killermist
  • 1,949
37

A DEBUG trap could be written to cancel commands that look suspicious. The following, or code similar to it, can be added to your ~/.bashrc:

shopt -s extdebug
checkcommand() {
  if [[ $BASH_COMMAND = 'rm -r'*' *' ]]; then
    echo "Suppressing rm -r command ending in a wildcard" >&2
    return 1
  fi
  # check for other commands here, if you like
  return 0
}
trap checkcommand DEBUG

Adjust the logic to taste.

(I don't actually expect this approach to be useful -- too many ways to mess up a command destructively to find them testing one-by-one -- but it provides a literal answer to the question).

8

Can you train yourself to use, say, rmrf in place of rm -rf?

If so, this bash function will provide you a chance to see what would actually happen before confirming the command:

rmrf() { echo rm -rf "$@"; read -p "Proceed (y/N)? "; [ "${REPLY,,}" = y ] && rm -rf "$@"; }

To make this function permanent, add this line to the ~/.bashrc file on each computer you use.

Comparison with the common rm alias

It is common to define an alias:

alias rm='rm -i'

This has two limitations:

  1. If you come to depend on this alias, then you will in for a shock when you are on a machine or in an environment that does not have it. By contrast, trying to run rmrf on a machine without that function will return a harmless command not found.

  2. This alias is no help in your case because the -f option that you supply on the command line overrides the -i option in the alias.

John1024
  • 17,343
6

If I am in a situation where deleting the wrong files is a really big deal, one of the things I've done is make a trashcan folder, like mkdir trashcan, and then I have a script rmTrashcan which has a rm -rf trashcan/* or rm -rf * or similar, written very carefully and checked several times.

That way, if I make a mistake, the mistake is on a mv command, not a rm command. Once I do a ls and am confident of exactly what I am deleting, a rmTrashcan actually does the dirty work safely.

It was also tremendously convenient for a situation where I had to delete backups. I could mv an entire month of backups into the trashcan, mv the few I wanted to keep (1st of month, 15th of month) back into the backups, then rmTranshcan the rest. Doing a similar command is hard to do with rm on its own, and doing it this way let me ls the backups to be confident in what files I am leaving behind (rather than just enumerating the files I intend to delete)

Cort Ammon
  • 2,376
4

Instead of bothering with two commands (ls and rm), I think a simpler and easier way is to use find:

find . -maxdepth 1 -name "string*" -delete

If you accidentally type "string *" it will delete files named string chars and string letters (which is what you wanted anyway), but it won't grab every file like * in a shell will.

Also, you can leave off the -delete to see which files it's going to delete, then hit up arrow and type -delete easier than typing ^ls -R^rm -rf or other nonsense.

nanny
  • 140
3

Is there a simple way to smartly protect against an accidental trailing or leading wildcard?

Not really. It’s proposed in another answer you could create a custom command to add a prompt before executing a task. But the problem with this custom command is it must be consciously installed on systems you are working on. And even if it is installed, the problem is your reflex to hit y to get the task done with could come into play.

Meaning this is all a user interface issue even if it is on a text/command line level. How many safety nets do you expect there to be to protect you from doing something you shouldn’t? It’s like a pair of scissors: If you are somehow negligent and slip and cut your hand while intending to cut cloth or paper, who is at fault? Or even traffic lights and stop signs: There’s really nothing stopping a driver from running a light or ignoring traffic signs other than an acute awareness of what might happen if they do engage in such risky behavior.

That said the best, realistic solution lies in system permissions for users as well as groups. That is the best/only real safety net to protect a user from themselves.

If you are working on a system where you are the only one accessing it, you might be tempted to just chmod 777 everything, but that is not the way a rational system is setup. Instead permissions should be something like 755 for all directories and 644 for all non-executable files. Executable files should be 755 at the least, but maybe even 744 if you only want others to read but not run the files.

Giacomo1968
  • 58,727
2

Try composing your initial rm command without the -f flag, but with -i instead, such that rm will prompt you for each file it intends to delete. For small recursive deletions, you can hold down the y key, once you're sure the command has been typed correctly. For large deletions, you can abort the operation, and use commandline history to carefully change the -i to a -f.

2

I teach everyone about the !$ = last argument in the last command trick:

% ls job[XYZ].*
jobX.out1
jobX.out2
[rest of the matches]

% rm !$

This allows an inspection of the wildcard expansion, and then use of the exact same glob pattern without the possibility of inserting a space before the *.

Also I suggest people never cut and paste a globbing wildcard pattern on a potentially destructive command line. Because in my own hands that has been a problem :)

A tech in my lab just made this mistake last week (3 months of work) - and yes we had a backup (1-day behind).

kael
  • 61
1

rm has -i and -I flags to confirm before every removal. In the past, some distributions have turned them on by default. This is a terrible idea. Give the user too many confirmation dialogs for normal operations and they'll begin to habitually confirm them. This just shifts the requirement to "be careful" (always a red flag) to a new and more annoying dialog. "Yes. Yes. Yes. Yes! YES! God damnit, stupid computer just delete the files YESYESYESYESYES--CRAP I MEANT NO! NOOOOOOO!" This is the "Yes, but I meant no" dialog problem. This answer provides a visual explanation of why confirmation dialogs come at the wrong time.

The sort of mistake you describe is a slip, "the performance of an action which was not what was intended". The user typically immediately recognizes the mistake and knows exactly how to fix it. Unfortunately, Unix does not give the user the opportunity, rm deletes the file immediately. Every other operating system solves this problem by allowing deletions to be undone, at least for a little while, by the use of the Trash.

There are various trash systems for Unix, and this answer is full of suggestions.

The question is to alias rm or not to alias rm. Pros to aliasing rm...

  1. You can't make the slip of forgetting to use the rm alternative.

Cons to aliasing rm...

  1. You might come to rely on it on systems which don't have it.
  2. Might cause problems when the disk is nearly full.
  3. Need infrastructure to periodically empty the trash.
  4. Have to be sure not to interfere with the expected behavior of rm in programs.
  5. Might not fully emulate rm.

If you follow the first argument too far, you wind up using vi (not vim, vi), csh (not tcsh, csh) and other antiquated utilities because they're universally available. Still, there is a danger of overcustomizing your environment. I prefer to take my utilities with me and to make that as easy as possible. YMMV.

Two and three are technical problems. They can be solved with a clever reaper job which checks the size of the trash and periodically cleans things up, similar to a tmpreaper. This can be a cron job, or a more clever version can make use of the various file system event infrastructures available on many desktop Linux distributions. This is not simple, and even harder to do efficiently. Its better to find an existing system than to try to make your own.

The fourth can be dealt with by making your new rm a shell alias, alias rm='trash', then it will not affect programs.

The fifth is a problem I leave for the reader to solve. rm doesn't have a lot of switches.

Schwern
  • 2,196
0

A very simple trick is to put -rf at the end: rm whatever* -rf
This reduce drasticaly the error rate, because you type more character after the *, so you have more time to see typos.
This does not solve everything. Just a simple everyday trick.

0

Everyone seems to be saying, "Be more careful", "Don't make an alias/confirmation prompt because you'll become habituated to not paying proper attention to it".

Cool, and everything. I mean, I don't think you should make an alias for rm (nor rmrf, since you could easily screw that up and type the real command).

But why can't you make an alias/script and call it, say, remove and only feed it one argument (eg $1)? The wildcard should be $2, because of the inadvertent space (amiright?) and thus your script/wrapper/alias won't be fed the second one. Yes, you can only do one set of deletions (with a wildcard) at a time, but that's the price you'd pay.

If I were writing something nice, I might have it tell me the number of files and directories it's planning on deleting, and the total size of stuff I was deleting, and then ask for a confirm, but that might impede your flow. Maybe make that a flag option on remove? (-i). You might also wish to do a check $1 to see if it's just a single wildcard and ask for a confirmation, and list which directory you're actually in.


As an aside, there are a number of rm replacements out there. Many are trying to be compliant with the UI desktop trash. Some of those might be worth looking into.

user3082
  • 143