Add the following to your ~/.bashrc
:
# Avoid duplicates
HISTCONTROL=ignoredups:erasedups
# When the shell exits, append to the history file instead of overwriting it
shopt -s histappend
# After each command, append to the history file and reread it
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"
You could do something like:
fixhist() {
local cmd histnum
cmd=$(HISTTIMEFORMAT=/ history 1)
histnum=$((${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%%[<*]*}))
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%%[<*]*}))
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.
Best Answer
No it doesn't load everything into memory, that would be an impractical way to design this. It uses buffers to buffer the output from the left side of the pipe, and then connect these buffers to the input of the command on the right side of the pipe.
The man page
man 7 pipe
has all the details, as well as this other U&L Q&A titled: How big is the pipe buffer?