コマンドを実行する時「あ、、間違ったコマンド打っちゃった・・😇」となる時はありませんか?
私は日常茶飯事でやってる気がします。笑
するとコマンドの履歴にはドンドン溜まらなくていいコマンドが溜まってしまいます。。
# コマンドの履歴
$ history -n 1
hd
op .
cat ~/.zsh_history
miss #誤って入力してしまったコマンド
git log
git log$ #誤って入力してしまったコマンド
history
今までの履歴から検索して再度コマンドを実行する、という事は良くあると思ってて
↑ のように miss
・git log$
・gti branch
のような
誤って打ってしまったコマンドが検索履歴に残り続けてしまうのもめんどくさいですよね。
そこで打ち間違えたコマンドもインクリメントサーチを使って消してしまおう!
という事をやってみます。
検証した環境
1 | fzf | 0.42.0(brew) |
インクリメントサーチでhistoryを消す
hisotryについて
historyコマンドとはbash
やzsh
などで使用出来るコマンド。
ユーザーが以前に入力したコマンドのリストを表示します。
$ history
op .
miss
git log
git log$
history
この一覧をどこに持っているか?というと
- bash・・~/.bash_history
- zsh・・~/.zsh_history
とシンプルに隠しファイルとして存在しています。
そのためファイルの中身を確認するとそのまま履歴が表示されます
$ cat ~/.zsh_history
op .
miss
git log
git log$
history
つまり
このファイルから履歴として表示したくない部分を削除すれば history
を打っても表示されなくなります!
grepを使って~/.zsh_historyから削除する
grepを使うと特定の文字列が入っている行を除外する事が簡単に出来ます!
$ grep -v "git" ~/.zsh_history > ~/.zsh_history_temp
-v
オプションは指定しないパターンに一致しない行のみを出力するオプション。
これによりgit
を含まれない行のみが残ったものが「~/.zsh_history_temp」に保存されます
$ cat ~/.zsh_history
op .
miss
git log
git log$
history
$ cat ~/.zsh_history_temp
op .
miss
history
インクリメントサーチで検索したコマンドをhistoryから削除する
本題です!
インクリメントサーチで検索したコマンドをhistoryから削除するコードです
シェル得意な方からするとシェルらしくない書き方なんだろうなぁ。。と思いつつ。笑
# インクリメントサーチで選んだコマンドをhistoryから削除
alias hd='delete-history-incremental-search'
#
# インクリメントサーチで選んだコマンド検索履歴から削除する
#
function delete-history-incremental-search () {
local SELECTED_COMMAND=$(history -n 1 | fzf)
# エスケープを押した場合や選択されていない場合は即時リターン
[ -z "$SELECTED_COMMAND" ] && return
echo -n "delete \"\e[31m${SELECTED_COMMAND}\e[m\" command from history?(y/N): "
if read -q; then
echo ""
# historyファイルを念のためバックアップ
cat ~/.zsh_history > ~/.zsh_history_backup
# 選択したコマンドをhistoryから削除
# NOTE:
# (基本は不要です) /usr/bin/ を指定しないと alias で設定したgrepが実行されて行数が自動的に入ってしまう
# grep -v xxx とすることで、xxxに一致しなかった内容を出力する
# また -F をつける事で、$や.のような正規表現対象の文字列もただの文字列として判断しgrepを実行する
# 新たなに _temp がついたファイルを作成し、最終的に元のファイルに上書きする
/usr/bin/grep -vF "${SELECTED_COMMAND}" ~/.zsh_history > ~/.zsh_history_temp && mv ~/.zsh_history_temp ~/.zsh_history
# shellを再起動しhistoryを読み込みなおす
exec $SHELL
else
echo ""
fi
}
これでhd
を実行し miss
・git log$
を消してみると
historyから無事消えました!! 🎉
インクリメントサーチには fzf
を使っています。
オプションも多く、見やすく使いやすくて私の手放せないコマンドの1つ。
ざっくりやっている内容は
- fzfで削除対象のコマンドを
SELECTED_COMMAND
に代入(5行目) - grepを使って検索したコマンドを除いたhisotryファイルを作成し上書きする(21行目)
となります。
grepコマンドについて
今回の肝となるgrep。
ポイントを何点か記載しておきます。
/usr/bin/ の指定
基本はこの設定は不要な方が多いと思います!
grepコマンドを拡張している人は参考にしてみて下さい
私の環境だとgrep
コマンドに対してaliasを設定しています
# grepを拡張したripgrepを使用。-n 行数表示, -I バイナリファイル無視
alias grep="rg -nI"
そのためgrep
を使うと上記alias版のgrepが使われて行数が表示されてしまい、
historyにうまく渡せないという問題があっため /usr/bin のgrepを利用し回避しました。
# grepをそのまま使うと検索結果に行数が表示されてしまう
$ cat ~/.zsh_history | grep "git"
cat ~/.zsh_history | grep "git"
3:git log
4:git log$
6:~/.zsh_history | grep "git"
・・・
# /usr/bin/grepを使う事で回避
$ cat ~/.zsh_history | /usr/bin/grep "git"
git log
git log$
~/.zsh_history | grep "git"
-vオプション
前述した通り、
-v
オプションを使う事で指定しないパターンに一致しない行のみを出力する事が出来ます
$ grep -v "git" ~/.zsh_history > ~/.zsh_history_temp
$ cat ~/.zsh_history
op .
miss
git log
git log$
history
$ cat ~/.zsh_history_temp
op .
miss
history
-Fオプション
-F
は--fixed-strings
オプションの省略記法。
正規表現の文字列も含め文字列として扱います
grepは基本的に正規表現を用いる事が可能です
# log という文字が入っているもの全てを取り出す
$ cat ~/.zsh_history | /usr/bin/grep "log"
docker-compose logs
firebase login
git log
git log$
# 正規表現により末尾が log のもののみを取り出す
$ cat ~/.zsh_history | /usr/bin/grep "log$"
git log
-F
をつける事で正規表現の文字も文字列としてみなしてくれます
# -F をつける事で正規表現の文字列(ここでは$)も関係なく検索が可能
$ cat ~/.zsh_history | /usr/bin/grep -F "log$"
git log$