Prevent duplicates from being saved in bash history [closed]
As far as I know, it is not possible to do what you want. I see this as a bug in bash's history processing that could be improved.
export HISTCONTROL=ignoreboth:erasedups # no duplicate entriesshopt -s histappend # append history fileexport PROMPT_COMMAND="history -a" # update histfile after every command
This will keep the in memory history unique, but while it does saves history from multiple sessions into the same file, it doesn't keep the history in the file itself unique. history -a
will write the new command to the file unless it's the same as the one immediately before it. It will not do a full de-duplication like the erasedups
setting does in memory.
To see this silliness in action, start a new terminal session, examine the history, and you'll see repeated entries, say ls
. Now run the ls
command, and all the duplicated ls
will be removed from the history in memory, leaving only the last one. The in memory history becomes shorter as you run commands that are duplicated in the history file, yet the history file itself continues to grow.
I use my own script to clean up the history file on demand.
# remove duplicates while preserving input orderfunction dedup { awk '! x[$0]++' $@}# removes $HISTIGNORE commands from inputfunction remove_histignore { if [ -n "$HISTIGNORE" ]; then # replace : with |, then * with .* local IGNORE_PAT=`echo "$HISTIGNORE" | sed s/\:/\|/g | sed s/\*/\.\*/g` # negated grep removes matches grep -vx "$IGNORE_PAT" $@ else cat $@ fi}# clean up the history file by remove duplicates and commands matching# $HISTIGNORE entriesfunction history_cleanup { local HISTFILE_SRC=~/.bash_history local HISTFILE_DST=/tmp/.$USER.bash_history.clean if [ -f $HISTFILE_SRC ]; then \cp $HISTFILE_SRC $HISTFILE_SRC.backup dedup $HISTFILE_SRC | remove_histignore >| $HISTFILE_DST \mv $HISTFILE_DST $HISTFILE_SRC chmod go-r $HISTFILE_SRC history -c history -r fi}
I'd love to hear more elegant ways to do this.
Note: the script won't work if you enable timestamp in history via HISTTIMEFORMAT.
Bash can improve the situation by
- fix
history -a
to only write new data if it does not match any history in memory, not just the last one. - de-deduplicate history when files are read if
erasedups
setting is set . A simplehistory -w
in a new terminal would then clean up the history file instead of the silly script above.
The problem is definitely the histappend
. Tested and confirmed on my system.
My relevant environment is:
$ set | grep HISTHISTFILE=/Users/hop/.bash_historyHISTFILESIZE=500HISTIGNORE=' *:&:?:??'HISTSIZE=500$ export HISTCONTROL=erasedups$ shopt | grep histcmdhist onhistappend offhistreedit offhistverify offlithist off
Now that I think about it, the problem is probably with the history -a
. history -w
should write the current history without any duplicates, so use that if you don't mind the concurrency issues.