I'm trying to prevent bash
from saving duplicate commands to my history. Here's what I've got:
我正在尝试阻止bash将重复命令保存到我的历史记录中。这是我得到的:
shopt -s histappend
export HISTIGNORE='&:ls:cd ~:cd ..:[bf]g:exit:h:history'
export HISTCONTROL=erasedups
export PROMPT_COMMAND='history -a'
This works fine while I'm logged in and .bash_history
is in memory. For example:
当我登录并且.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
But when I log back in, my history file looks like this:
但是当我重新登录时,我的历史文件看起来像这样:
$ 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
What am I doing wrong?
我究竟做错了什么?
EDIT: Removing the shopt
and PROMPT_COMMAND
lines from .bashrc
does not fix the problem.
编辑:从.bashrc中删除shopt和PROMPT_COMMAND行不能解决问题。
5 个解决方案
#1
33
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.
据我所知,不可能做你想做的事。我认为这是bash历史处理中可以改进的错误。
export HISTCONTROL=ignoreboth:erasedups # no duplicate entries
shopt -s histappend # append history file
export 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.
这将使内存历史记录保持唯一,但它确实将多个会话的历史记录保存到同一文件中,但它不会使文件本身的历史记录保持唯一。 history -a会将新命令写入文件,除非它与之前的命令相同。它不会像擦除设置在内存中那样进行完全重复数据删除。
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.
要看到这种愚蠢的行为,开始一个新的终端会议,检查历史,你会看到重复的条目,比如说ls。现在运行ls命令,所有重复的ls将从内存中的历史记录中删除,只留下最后一个。当您运行历史文件中重复的命令时,内存历史记录会变短,但历史记录文件本身会继续增长。
I use my own script to clean up the history file on demand.
我使用自己的脚本按需清理历史文件。
# 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
}
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.
注意:如果通过HISTTIMEFORMAT在历史记录中启用时间戳,则脚本将不起作用。
Bash can improve the situation by
Bash可以改善这种状况
- 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.
修复历史记录-a如果它与内存中的任何历史记录都不匹配,则只写入新数据,而不仅仅是最后一个。
如果设置了erasedups设置,则在读取文件时去除重复数据删除历史记录。然后,新终端中的简单历史记录将清除历史文件而不是上面的愚蠢脚本。
#2
7
The problem is definitely the histappend
. Tested and confirmed on my system.
问题绝对是他的意见。在我的系统上测试并确认。
My relevant environment is:
我的相关环境是:
$ 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
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.
现在我考虑一下,问题可能在于历史--a。历史记录-w应该在没有任何重复的情况下编写当前历史记录,因此如果您不介意并发问题,请使用它。
#3
5
export HISTCONTROL=ignoreboth
#4
2
Here is what I use..
这是我用的..
[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@ ~]$
and working
[vanuganti@ ~]$ pwd
/Users/XXX
[vanuganti@ ~]$ pwd
/Users/XXX
[vanuganti@ ~]$ history | grep pwd | wc -l
1
#5
1
inside your .bash_profile add
在你的.bash_profile内添加
alias hist="history -a && hist.py"
then put this on your path as hist.py and make it executable
然后将它作为hist.py放在你的路径上并使其可执行
#!/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
now when you want the short list just type hist
现在当你想要短名单时只需输入hist
#1
33
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.
据我所知,不可能做你想做的事。我认为这是bash历史处理中可以改进的错误。
export HISTCONTROL=ignoreboth:erasedups # no duplicate entries
shopt -s histappend # append history file
export 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.
这将使内存历史记录保持唯一,但它确实将多个会话的历史记录保存到同一文件中,但它不会使文件本身的历史记录保持唯一。 history -a会将新命令写入文件,除非它与之前的命令相同。它不会像擦除设置在内存中那样进行完全重复数据删除。
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.
要看到这种愚蠢的行为,开始一个新的终端会议,检查历史,你会看到重复的条目,比如说ls。现在运行ls命令,所有重复的ls将从内存中的历史记录中删除,只留下最后一个。当您运行历史文件中重复的命令时,内存历史记录会变短,但历史记录文件本身会继续增长。
I use my own script to clean up the history file on demand.
我使用自己的脚本按需清理历史文件。
# 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
}
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.
注意:如果通过HISTTIMEFORMAT在历史记录中启用时间戳,则脚本将不起作用。
Bash can improve the situation by
Bash可以改善这种状况
- 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.
修复历史记录-a如果它与内存中的任何历史记录都不匹配,则只写入新数据,而不仅仅是最后一个。
如果设置了erasedups设置,则在读取文件时去除重复数据删除历史记录。然后,新终端中的简单历史记录将清除历史文件而不是上面的愚蠢脚本。
#2
7
The problem is definitely the histappend
. Tested and confirmed on my system.
问题绝对是他的意见。在我的系统上测试并确认。
My relevant environment is:
我的相关环境是:
$ 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
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.
现在我考虑一下,问题可能在于历史--a。历史记录-w应该在没有任何重复的情况下编写当前历史记录,因此如果您不介意并发问题,请使用它。
#3
5
export HISTCONTROL=ignoreboth
#4
2
Here is what I use..
这是我用的..
[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@ ~]$
and working
[vanuganti@ ~]$ pwd
/Users/XXX
[vanuganti@ ~]$ pwd
/Users/XXX
[vanuganti@ ~]$ history | grep pwd | wc -l
1
#5
1
inside your .bash_profile add
在你的.bash_profile内添加
alias hist="history -a && hist.py"
then put this on your path as hist.py and make it executable
然后将它作为hist.py放在你的路径上并使其可执行
#!/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
now when you want the short list just type hist
现在当你想要短名单时只需输入hist