50

bash重複したコマンドを履歴に保存しないようにしています。これが私が持っているものです:

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

これは、ログインして.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

しかし、再度ログインすると、履歴ファイルは次のようになります。

$ 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

私は何を間違っていますか?

shopt編集: andPROMPT_COMMAND行を削除して.bashrcも問題は解決しません。

4

5 に答える 5

39

私の知る限り、あなたが望むことをすることは不可能です。これは、改善できる bash の履歴処理のバグだと思います。

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

これにより、メモリ内の履歴が一意に保たれますが、複数のセッションからの履歴が同じファイルに保存されますが、ファイル自体の履歴は一意に保たれません。history -a直前のコマンドと同じでない限り、新しいコマンドをファイルに書き込みます。erasedups設定がメモリ内で行うように、完全な重複除外は行いません。

このばかげた動作を確認するには、新しい端末セッションを開始し、履歴を調べます。たとえば、繰り返しエントリが表示されますls。コマンドを実行するlsと、複製lsされたものはすべてメモリ内の履歴から削除され、最後のものだけが残ります。履歴ファイルで複製されたコマンドを実行すると、メモリ内の履歴は短くなりますが、履歴ファイル自体は大きくなり続けます。

独自のスクリプトを使用して、必要に応じて履歴ファイルをクリーンアップします。

# 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 を使用して履歴のタイムスタンプを有効にすると、スクリプトは機能しません。

Bash は次の方法で状況を改善できます。

  1. history -a最後の履歴だけでなく、メモリ内の履歴と一致しない場合にのみ新しいデータを書き込むように修正しました。
  2. erasedups設定が setの場合、ファイルの読み取り時に履歴を重複排除します。history -w上記のばかげたスクリプトの代わりに、新しい端末で単純に履歴ファイルをクリーンアップします。
于 2011-09-16T19:22:13.547 に答える
7

問題は間違いなくhistappend. 私のシステムでテストされ、確認されました。

私の関連する環境は次のとおりです。

$ 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 -a. history -w重複なしで現在の履歴を書き込む必要があるため、同時実行の問題を気にしない場合はそれを使用してください。

于 2008-12-03T20:34:06.893 に答える
5
export HISTCONTROL=ignoreboth
于 2008-12-03T19:17:04.710 に答える
3

これが私が使用するものです..

[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
于 2011-01-08T01:40:53.257 に答える
2

.bash_profile 内に追加

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

次に、これを hist.py としてパスに配置し、実行可能にします

#!/usr/bin/env python

from __future__ import print_function
import os, sys
home = os.getenv("HOME")
if not home :
    sys.exit(1)
lines = open(os.path.join(home, ".bash_history")).readlines()
history = []
for s in lines[:: -1] :
    s = s.rstrip()
    if s not in history :
        history.append(s)
print('\n'.join(history[:: -1]))

短いリストが必要な場合は、 hist と入力するだけです

于 2011-01-08T18:23:09.280 に答える