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
削除しても問題は解決しません。PROMPT_COMMAND
.bashrc
ベストアンサー1
私の知る限り、あなたが望むことを行うことはできません。これは 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
メモリ内の履歴から削除され、最後の 1 つだけが残ります。履歴ファイルに重複しているコマンドを実行すると、メモリ内の履歴は短くなりますが、履歴ファイル自体は大きくなり続けます。
独自のスクリプトを使用して、必要に応じて履歴ファイルをクリーンアップします。
# 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は状況を改善できる
history -a
最後のデータだけでなく、メモリ内のどの履歴とも一致しない場合にのみ新しいデータを書き込むように修正しました。erasedups
設定がされている場合、ファイルの読み取り時に履歴の重複を排除します。history -w
新しいターミナルで単純な操作を行うと、上記の愚かなスクリプトの代わりに履歴ファイルがクリーンアップされます。