1

Is there a way to prevent deletion of system/shell aliased folders? I want these commands to fail. My shell is bash.

Such as:

$rm -rf .
$rm -rf ..
$rm -rf ~
$rm -rf *
4

3 Answers 3

3

Note that ~ and * are expanded by the shell before passing the arguments to rm.

The only way to do it is to define a function named rm that parses the arguments before invoking command rm ...

I would not recommend it. When you get lazy, you get in trouble when you sit at some other computer without your self-protections. I used to alias rm="rm -i" before that bit me.

2
  • alias rm="rm -I" is more permissive than -i, I use this. I think these kind of aliases are necessary to prevent these mistakes, its not wise to write commands you know rely on this behaviour though.
    – Graeme
    Jan 10, 2014 at 22:10
  • 1
    If you define a function, that function will see the result of the expansion (/home/glenn, not ~, the list of files, not *) Jan 11, 2014 at 9:47
2

Not sure if there is an answer to this, but one thing I do in my .bashrc is to set GLOBIGNORE=.:.., this stops glob expansions from matching . and ... It also effectively enables dotglob which might not be what you want (GLOBIGNORE=.:..:.* stops this). I find this useful for me.

2

With recent versions of bash:

typetext() {
  perl -le 'require "sys/ioctl.ph";
    ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV' "$@"
}
checkrm() {
  local re='\<rm\>.*[[:blank:]]([.*~]|\.\.)([[:blank:]]|$)'
  if [[ $READLINE_LINE =~ $re ]]; then
    printf > /dev/tty "Are you sure? "
    read -n1 k
    echo
    if [[ $k != [yY] ]]; then
      READLINE_LINE=
      return
    fi
  fi
  typetext $'\n'
}  <> /dev/tty >&0
bind -x '"\C-m": checkrm'

Basically, upon pressing Return, our checkrm function is invoked.

It looks in the currently entered command line ($READLINE_LINE for which you need bash 4.3 or newer) for a rm word (also matches /bin/rm, but not in rmdir) followed by a *, ., ~ or .. argument.

If it matches, it prompts the user for confirmation. If confirmed, a newline character is inserted in tty input buffer for the command to be accepted (both CR and LF are bound to accept line, we're only wrapping CR); if not, the current buffer is emptied.

Note that with versions of bash prior to 4.4, there was a hitting a bug that caused readline to stop functioning properly when a job was suspended.

6
  • 1. Load the above into bash. Start emacs -nw. Suspend emacs C-z and type: no visible output. Go back to emacs fg and exit emacs. Back at the prompt, whatever you type is invisible.
    – grebneke
    Mar 6, 2014 at 17:17
  • 2. I have a hard time understanding \<rm\> - why not just rm? What are the \<\> and where are they documented? Tried ERE docs but cannot find an explanation.
    – grebneke
    Mar 6, 2014 at 17:22
  • Found it: regarding \<\>, it's a GNU Extension, matching empty string at beginning and end of word, respectively.
    – grebneke
    Mar 6, 2014 at 19:08
  • @grebneke, I can reproduce your 1 above and it looks like a bug in bash. Binding an external command to ^M (like bind -x '"\C-m": /bin/true') is enough to trigger it (use Ctrl+J to accept the line as we do in our TIOCSTI ioctl). Mar 6, 2014 at 20:54
  • 1
    @grebneke, technically, \<\> is more of a BSD extension (was already in ex in the late 70s). It never made it to POSIX basic regular expressions. But has been in GNU regexps for a while if not the beginning. bash is the GNU shell, but I think it uses the system's regex library for its regexps, so it may not work on non-GNU/BSD systems. Apr 14, 2016 at 8:34

You must log in to answer this question.

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