I cannot remember how many times I've listed a subdirectory and executed /bin/rm -f *
in the current directory. Can anyone give suggestions to help me avoid this? What should I do if I want the system to warn me of the danger when I try to execute /bin/rm -f *
?
4 Answers
zsh
by default asks you for confirmation, when you try and run any command called rm
with *
as a whole word on the command line (a feature inherited from tcsh
though in tcsh
it's not enabled by default).
$ rm -rf *
zsh: sure you want to delete all the files in / [yn]?
If you have to use bash, with recent versions of bash
, you could do something approaching by using extdebug
and the DEBUG
trap:
shopt -s extdebug
check_for_rm_star() {
case $1 in
(rm*[\ /]"* "* | rm*[\ /]\*)
read -p "check_for_rm_star: Are you sure? " -n1 answer < /dev/tty > /dev/tty
echo > /dev/tty
[[ $answer == [yY] ]]
esac
}
trap 'check_for_rm_star "$BASH_COMMAND"' DEBUG
That's a simplistic one that would work for rm *
and the most common cases but not for instance for rm "*"
or /bin/rm *
or : $(rm *)
, but you get the idea. Ideally, we'd need to parse $BASH_COMMAND
the same was as the shell does to see if the first argument expands to rm
or */rm
, and to see if it's passed an unquoted *
, but that can't really be done in a bulletproof fashion.
-
Thanks Stephance! I like this recognization of
*
. I wonder if there is way to achieve this inbash
.– ct586Mar 25, 2013 at 12:59 -
-
Great! Thanks for giving me weighty reason to postpone the "I'll try zsh someday" indefinitely (I like Unix not trying to second guess me).– vonbrandMar 25, 2013 at 16:05
-
-
Impressive! I do need to unalias my rm and add this to my bash configuration file. When (/bin/rm*[\ /]"* "* | /bin/rm*[\ /]*) is added to
case
block, it can catch /bin/rm * also.– ct586Mar 26, 2013 at 6:08
One possibility is to create a shell alias to map rm
to a less destructive command. For instance:
alias rm='trash' # from the package trash-cli
This does not delete the files, but places them in the trash bin, so you can restore them. However, this changes the semantics of the rm
command (you can delete entire directories without -r
, for example). Furthermore, it does not help if the full path is used.
Another possibility is to set up a regular backup, say once per hour. That way you can happily delete files and restore them later.
-
1The problem with aliases is that that they don't get used if you type the full path to the command, as the OP does in his example. To guard against that, you really do need to replace /bin/rm with something else. And on a system used by others, that could be unacceptable. (it would be to me.)– Tim BMar 25, 2013 at 12:35
-
You're totally right. But if someone requests
/bin/rm
(s)he expectsrm
with the known semantics. I would never replacerm
system-wide. If that's really an issue for several users (a single user can always create a localrm
and adjust the PATH) I would consider a frequent backup and let the users learn the hard way thatrm
deletes files.– MarcoMar 25, 2013 at 12:40 -
Thanks Marco! I have already set this for my regular usage. Sometimes I want to execute
/bin/rm -f *
and also I want a hint to tell me"Are you sure?"
.– ct586Mar 25, 2013 at 12:45 -
The backup system will reduce the loss of misoperation. I have a backup system for other folders but not this one. Maybe I should backup this also.– ct586Mar 25, 2013 at 12:51
-
If you want the asterisk to trigger some unique behavior, only the shell can do that. (Globbing must occur prior to exec) If that feature is something you want, then as Stephane notes, switching to zsh is one way to get it. It is still a bourne-ish shell, so it might not feel too alien.– Tim BMar 25, 2013 at 13:26
The only way to do that is to replace rm itself.
There is a wrapper script for rm that purports to provide a safe rm, which can be found at LaunchPad. From that page:
Safe-rm is a safety tool intended to prevent the accidental deletion of important files by replacing /bin/rm with a wrapper, which checks the given arguments against a configurable blacklist of files and directories that should never be removed.
The only issue I see with that is your example "dangerous" rm example is run with the full path, /bin/rm
. So you couldn't put this wrapper script in a directory earlier in your $PATH, and let it get found when you run rm, and have the unwrapped "normal" rm available by typing the full path, /bin/rm, as you do above.
-
Thanks Tim! This could be a great way to protect system files. However, the blacklist for personal usage could be very large and flexible.– ct586Mar 25, 2013 at 12:49
-
It's just a perl script. You customize it into any behavior that suits you. But as others have pointed out, you used an alias to make rm safer, but then developed the habit of typing the full path /bin/rm explicitly to avoid that safety net.– Tim BMar 25, 2013 at 13:07
-
One simple solution is to add the alias rm="rm -i"
, then you will get asked before each removal if you are sure. But, as pointed out by one of my teachers, this might fool you that the unix system you are using is a safe and warm place, and that might be even more dangerous than accidentally running rm *
-
4This answer is wrong. The
-f
option overwrites-i
and renders it useless.– MarcoMar 25, 2013 at 12:30 -
1
-
Thanks, Kotte! But this can not solve my problem just as Maceo and Tim B said.– ct586Mar 25, 2013 at 12:40
-
yeah, this doesn't help very much if you use absolute paths. But I really wanted to share the teaching of my professor ;)– KotteMar 26, 2013 at 15:56
rm
binary in combination with the-f
flag is a strong indicator that you really want to delete the files. You should change your habits and not your system.rm
and the like, it will screw you over whenever you're using a different machine. Also you can use\rm
to circumvent the alias.