zshのhistoryをインクリメントサーチで削除する

投稿日
zshのhistoryをインクリメントサーチで削除する

コマンドを実行する時「あ、、間違ったコマンド打っちゃった・・😇」となる時はありませんか?

私は日常茶飯事でやってる気がします。笑




するとコマンドの履歴にはドンドン溜まらなくていいコマンドが溜まってしまいます。。

# コマンドの履歴
$ history -n 1
hd
op .
cat ~/.zsh_history
miss #誤って入力してしまったコマンド
git log
git log$  #誤って入力してしまったコマンド
history



今までの履歴から検索して再度コマンドを実行する、という事は良くあると思ってて

↑ のように missgit log$gti branch のような

誤って打ってしまったコマンドが検索履歴に残り続けてしまうのもめんどくさいですよね。



そこで打ち間違えたコマンドもインクリメントサーチを使って消してしまおう!

という事をやってみます。

検証した環境

1 fzf 0.42.0(brew)

インクリメントサーチでhistoryを消す

hisotryについて

historyコマンドとはbashzshなどで使用出来るコマンド。

ユーザーが以前に入力したコマンドのリストを表示します。

$ 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から削除するコードです


シェル得意な方からするとシェルらしくない書き方なんだろうなぁ。。と思いつつ。笑
~/zshrc
# インクリメントサーチで選んだコマンドをhistoryから削除
alias hd='delete-history-incremental-search'
~/.zshrc
#
# インクリメントサーチで選んだコマンド検索履歴から削除する
#
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を実行し missgit 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$
プロフィール画像
Yuki Takara
都内でフリーランスのエンジニアをやってます。フロントとアプリ開発メインに幅広くやってます。