This article introduces how to implement a prompt that warns before executing the “rm -rf *” command on the command line in the Bash programming language (scripting language) for Linux PCs and servers.
<>
rm -rf is famous as one of the most dangerous commands
</>
This time, I’ll introduce code I wrote with the idea of reducing the danger of the rm -rf command even a little.
Usage Example

$ tmpdird # Move to new directory
$ ls
total 0
166351711236005864 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 ..
23080948093026057 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 .
$ genfiles 3 # Generate files
$ ls
total 0
166351711236005864 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 ..
8444249304069546 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 3.txt
23080948093026057 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 .
51509920740553578 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 2.txt
36310271996515302 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 1.txt
$ rm -rf * # Delete all files > confirmation prompt > n
W: It seems You are attempting to run kind of dangerous command. Continue? [y/n]
n
$ ls # Confirm files are not deleted
total 0
166351711236005864 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 ..
8444249304069546 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 3.txt
23080948093026057 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 .
51509920740553578 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 2.txt
36310271996515302 -rwxrwxrwx 1 yuis yuis 2 Jul 10 21:59 1.txt
$ rm -rf * # Delete all files > confirmation prompt > y
W: It seems You are attempting to run kind of dangerous command. Continue? [y/n]
y
$ ls # Confirm files are deleted
total 0
166351711236005864 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 ..
23080948093026057 drwxrwxrwx 1 yuis yuis 4096 Jul 10 21:59 .
As shown above, when you try to execute rm -rf *, a warning prompt appears before execution. y executes it, and n cancels execution.
Code
ok(){
: <<< '
yes or no prompt
e.g. printf "The file alredy exist here. Override it? " ; ok && echo y || echo n
'
read -n 1 -r ; [[ $REPLY =~ ^[Yy]$ ]] && { echo ; return 0 ; } || { echo ; return 1 ; }
}
red='\e[1;31m'
grn='\e[1;32m'
yel='\e[1;33m'
blu='\e[1;34m'
mag='\e[1;35m'
cyn='\e[1;36m'
end='\e[0m'
warn(){
printf "${yel}W: ${*}\n${end}" >&2
}
##
shopt -s extdebug
preexec_invoke_exec () {
[ -n "$COMP_LINE" ] && return # do nothing if completing
[ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
local this_command=`HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//"`;
# So that you don't get locked accidentally
if [ "shopt -u extdebug" == "$this_command" ]; then
return 0
fi
# // filtering
# Modify $this_command and then execute it
# eval "${this_command}"
# echo "${this_command}"
if [[ "${this_command}" =~ ^(somethingdangercommand$|somethingdangercommand[[:space:]]) ]]; then warn "It seems You are attempting to run kind of dangerous command. Continue? [y/n]" ; ok && eval "${this_command}" || return
elif [[ "${this_command}" =~ ^(anotherSomethingdangercommand$|anotherSomethingdangercommand[[:space:]]) ]]; then warn "It seems You are attempting to run kind of dangerous command. Continue? [y/n]" ; ok && eval "${this_command}" || return
elif [[ "${this_command}" =~ ^(rm[[:space:]][-rf]{3}$|rm[[:space:]][-rf]{3}[[:space:]]) ]]; then warn "It seems You are attempting to run kind of dangerous command. Continue? [y/n]" ; ok && eval "${this_command}" || return
else eval "${this_command}"
fi
# // filtering
return 1 # This prevent executing of original command
}
trap 'preexec_invoke_exec' DEBUG
Add the above code to ${HOME}/.bashrc, and try executing an undefined command, somethingdangercommand. Since it’s an undefined command, normally you would get an error saying it’s undefined, but by entering n at the prompt, the command itself is not executed, so it exits without an error.
trap ‘preexec_invoke_exec’ DEBUG … Execute preexec_invoke_exec() before each command execution
elif [[ ”${this_command}” =~ ^(rm[[:space:]][-rf]{3}$|rm[[:space:]][-rf]{3}[[:space:]]) ]]; then warn “It seems You are attempting to run kind of dangerous command. Continue? [y/n]” ; ok && eval ”${this_command}” || return … Warn when the executed command is rm -rf or rm -fr
Before executing a command, it filters whether the command matches a regular expression, etc., and if caught by the filter, it warns; otherwise, it evals the passed command as usual.
References
- Linux trap command help and examples
- linux - Modify all bash commands through a program before executing them - Unix & Linux Stack Exchange
Conclusion
It seems that rm -rf accidents often happen due to exclamation expansion. If you’re not using it, it’s good to disable it.
# disable/turn off history expansion `!` altogether
set +H