bash の history からコマンドを実行できなくする & コマンドの履歴は見られるようにする設定
bash で以前実行したコマンドを ↑ キーや Ctrl+p、Ctrl+r で検索すると思います。
このとき、
- 以前実行したコマンドの引数を一部変えて実行したいから history からコマンドを探して一部だけ書き換えようと思っていたのに間違えて Enter を押してそのまま実行してしまった
- ↑ キーや Ctrl+p で履歴を辿っている途中に間違ったコマンドを実行してしまった
などのオペレーションミスをしたことがある方、いらっしゃると思います(ローカル環境とリモート環境を行ったり来たりしているとミスしがちな気がします)。
history を保存しないようにすれば(set +o history
など)上記のようなオペレーションミスは防げそうですが、コマンドの履歴が見られないのは不便です。
そこで、history からコマンドを実行できなくしつつ、コマンドの履歴は見られるようにする設定を検証しました。
検証環境は
- GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu) # Amazon Linux 2016.03, 2016.09, CentOS 7 - GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu) # Debian 8.5
です。
CentOS6 の GNU bash, version 4.1.2(2)-release (x86_64-redhat-linux-gnu)
では動作しませんでした…
#export HISTTIMEFORMAT='%FT%T%z ' #export HISTFILE=/path/to/.bash_history shopt -u histappend export PROMPT_COMMAND='history -a; history -c;'
PROMPT_COMMAND
を使ってコマンド実行後に history -a
でコマンドの履歴を HISTFILE
に追記し、 history -c
で history を削除しています。
history -a
で追記しているので histappend
は無効にしています。
時間を記録しなくてよければ HISTTIMEFORMAT
は設定不要ですし、HISTFILE
もデフォルトの設定で良ければ書く必要はないです。
この設定をした状態でコマンドを実行すると HISTFILE
には保存されつつ、↑キーなどでコマンドを探すことはできなくなります。
コマンドの履歴を見たいときは HISTFILE
を直接見れば OK です。
ただし、!!
や !$
のような直前のコマンドや引数を参照する機能は使えなくなりますので注意してください。
おまけ
HISTTIMEFORMAT
を指定した状態の HISTFILE
は以下のようになります。
$ cat $HISTFILE #1488171696 ls #1488171701 echo foo
これだとちょっと読みにくいので整形する関数を用意しておくと便利です。
read_history() { awk 'NR % 2 { gsub("#", "", $0); t=strftime("%FT%T%z", $0); next } {print t, $0}' $HISTFILE }
read_history
を実行すると以下のようになります。
2017-02-27T05:01:36+0000 ls 2017-02-27T05:01:41+0000 echo foo
読みやすくはなりましたが、毎回 grep したりするのは面倒なので peco を使っていい感じに見られるようにしてみます。
peco_history() { awk 'NR % 2 { gsub("#", "", $0); t=strftime("%FT%T%z", $0); next } {print t, $0}' $HISTFILE | peco } bind -x '"\C-r": peco_history'
これで Ctrl-r でコマンドの履歴が見られるようになります。
追記
※追記1 2017/03/01 16:38
DEBUG を trap すれば CentOS6 でも似たようなことはできました。
※追記2 2017/03/01 18:50
この機能が欲しいと思ったことはないけど、履歴を書き出すときに先頭に # を追加してコメント化して保存するのではダメなんだろうか。 - n314 のコメント / はてなブックマーク
というコメントをいただいたので、
bash で特定のコマンドを実行前にキャンセルする - tkuchikiの日記
のように DEBUG を trap して #
を追加するのを試してみました。
preexec
でコマンドを HISTFILE
に書き出すときに #
を先頭につけて history -r
で HISTFILE
を history に読み込むようにしたらできました。
preexec() { [ -n "${COMP_LINE}" ] && return [ "${BASH_COMMAND}" = "${PROMPT_COMMAND}" ] && return local cmd_history=$(HISTTIMEFORMAT='%F %T%z ' history 1) #local cmdtime=$(date -d "$(echo ${cmd_history} | perl -lane 'print join(" ", @F[1 .. 2]);')" +%s) local cmd=$(echo ${cmd_history} | perl -lane 'print join(" ", @F[3 .. $#F]);') [ "${cmd}" = "" ] && return (echo "#${cmdtime}" ; echo "#${cmd}") >> $HISTFILE history -r $HISTFILE }
(もしかして、こんなめんどくさいことしなくてもできる?)