防止重复被保存在bash历史中

我试图阻止bash保存重复的命令到我的历史logging。 这是我得到的:

 shopt -s histappend export HISTIGNORE='&:ls:cd ~:cd ..:[bf]g:exit:h:history' export HISTCONTROL=erasedups export PROMPT_COMMAND='history -a' 

这工作正常,而我login和.bash_history在内存中。 例如:

 $ history 1 vi .bashrc 2 vi .alias 3 cd /cygdrive 4 cd ~jplemme 5 vi .bashrc 6 vi .alias $ vi .bashrc $ history 1 vi .alias 2 cd /cygdrive 3 cd ~jplemme 4 vi .alias 5 vi .bashrc $ vi .alias $ history 1 cd /cygdrive 2 cd ~jplemme 3 vi .bashrc 4 vi .alias $ exit 

但是当我重新login时,我的历史文件如下所示:

 $ history 1 vi .bashrc 2 vi .alias 3 cd /cygdrive 4 cd ~jplemme 5 vi .bashrc 6 vi .alias 7 vi .bashrc 8 vi .alias 

我究竟做错了什么?

编辑:从.bashrc中删除shoptPROMPT_COMMAND行不能解决问题。

据我所知,做你想做的事是不可能的。 我把这看作是bash历史处理中一个可以改进的bug。

 export HISTCONTROL=ignoreboth:erasedups # no duplicate entries shopt -s histappend # append history file export PROMPT_COMMAND="history -a" # update histfile after every command 

这将保持内存历史logging的独特性,但它确实将历史logging从多个会话保存到同一个文件中,而不会将历史logging保存在文件本身中。 history -a会将新命令写入文件,除非它与之前的文件相同。 它不会像erasedups设置在内存中那样执行完全的重复数据删除。

要看到这个愚蠢的行为,开始一个新的terminal会议,检查历史,你会看到重复的条目,说ls 。 现在运行ls命令,将所有重复的ls从内存中的历史logging中删除,只留下最后一个。 在运行历史文件中重复的命令时,内存中的历史logging会变得更短,但是历史logging文件本身不断增长。

我使用自己的脚本按需清理历史文件。

 # remove duplicates while preserving input order function dedup { awk '! x[$0]++' $@ } # removes $HISTIGNORE commands from input function 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 entries function 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 } 

我很乐意听到更优雅的方式来做到这一点。

注意:如果您通过HISTTIMEFORMAT在历史logging中启用时间戳,脚本将不起作用。

Bash可以通过改善情况

  1. 修复history -a只写入新的数据,如果它不匹配内存中的任何历史logging,不只是最后一个。
  2. 如果设置了erasedups设置,则在读取文件时去除重复历史logging。 一个简单的history -w在一个新的terminal将清理历史文件,而不是上面的愚蠢的脚本。

这个问题绝对是组织支持。 在我的系统上testing并确认。

我的相关环境是:

 $ set | grep HIST HISTFILE=/Users/hop/.bash_history HISTFILESIZE=500 HISTIGNORE=' *:&:?:??' HISTSIZE=500 $ export HISTCONTROL=erasedups $ shopt | grep hist cmdhist on histappend off histreedit off histverify off lithist off 

现在我想到了,这个问题可能是history -ahistory -w应该写没有任何重复的当前历史,所以使用,如果你不介意并发问题。

 export HISTCONTROL=ignoreboth 

这是我用的..

 [vanuganti@ ~]$ grep HIST .alias* .alias:HISTCONTROL="erasedups" .alias:HISTSIZE=20000 .alias:HISTIGNORE=ls:ll:"ls -altr":"ls -alt":la:l:pwd:exit:mc:su:df:clear:ps:h:history:"ls -al" .alias:export HISTCONTROL HISTSIZE HISTIGNORE [vanuganti@ ~]$ 

和工作

 [vanuganti@ ~]$ pwd /Users/XXX [vanuganti@ ~]$ pwd /Users/XXX [vanuganti@ ~]$ history | grep pwd | wc -l 1 

在您的.bash_profile添加

 alias hist="history -a && hist.py" 

然后把这个作为hist.py的path,并使其可执行

 #!/usr/bin/env python f = open('/Users/joe/.bash_history') l = f.readlines() l.reverse() short = [] for s in l: if s.rstrip() not in short: short.append(s.rstrip()) short.reverse() for s in short: print s 

现在当你想要短列表只需inputhist