You could do something like:
fixhist() {
local cmd histnum
cmd=$(HISTTIMEFORMAT=/ history 1)
histnum=$((${cmd%%cmd%%[*/*]*}))
cmd=${cmd#*/} # remove the histnum
case $cmd in
(rm\ *|mv\ *|...)
history -d "$histnum" # delete
history -s "#$cmd" # add back with a #
esac
}
PROMPT_COMMAND=fixhist
The idea being that before each prompt, we check the last history entry (history 1) and if it's one of the dangerous ones, we delete it (history -d) and add it back with a # with history -s.
(obviously, you need to remove your HISTIGNORE setting).
An unwanted side effect of that though is that it alters the history time of those rm, mv... commands.
To fix that, an alternative could be:
fixhist() {
local cmd time histnum
cmd=$(HISTTIMEFORMAT='<%s>' history 1)
histnum=$((${cmd%%<*cmd%%[<*]*}))
time=${cmd%%>*}
time=${time#*<}
cmd=${cmd#*>}
case $cmd in
(rm\ *|mv\ *|...)
history -d "$histnum" # delete
HISTFILE=/dev/stdin history -r <<EOF
#$time
#$cmd
EOF
esac
}
PROMPT_COMMAND=fixhist
This time, we record the time of the last history, and to add back the history line, we use history -r from a temporary file (the here document) that includes the timestamp.
You'd want the fixhist to be performed before your history -a; history -c; history -r. Unfortunately, the current version of bash has a bug in that history -a doesn't save that extra line that we've added. A work around is to write it instead:
fixhist() {
local cmd time histnum
cmd=$(HISTTIMEFORMAT='<%s>' history 1)
histnum=$((${cmd%%<*cmd%%[<*]*}))
time=${cmd%%>*}
time=${time#*<}
cmd=${cmd#*>}
case $cmd in
(rm\ *|mv\ *|...)
history -d "$histnum" # delete
history -a
[ -f "$HISTFILE" ] && printf '#%s\n' "$time" "$cmd" >> "$HISTFILE";;
(*)
history -a
esac
history -c
history -r
}
PROMPT_COMMAND=fixhist
That is to append the commented command to the HISTFILE ourselves instead of letting history -a do it.