suin.io

Shellライフをそこそこ快適に!僕のこだわりzsh設定

suin2017年1月23日

zshいいですよね。育てればどんどん便利になっていきますね。ところで最近、MacBook Proを買い替えました。過去にCodeIQに寄稿した記事で『【図解】ゼロから始めるモダンなコマンドライン環境作り』というのがあり多くの方に読んでいただいたものがあるのですが、その中に掲載したzshrcの設定が古くなったのもあり、買い替えのタイミングで見直してみることにしました。

今回はメンテしやすいようにできるだけシンプルに…!と思いましたが、便利なツールをホイホイ入れた結果、行数的には増してしまいました。ヘビーzsherの方にとっては定番のものばかりだと思いますが、恥を恐れずに晒して行きたいと思います。

説明の都合上zshrcの内容は部分部分を紹介する形になるので、完全版は僕のGitHubをご覧いただければと思います。

ところどころ出てくる: "..." && { ... }は拙筆『シェルスクリプトの処理境界が鮮明になる「名前付きブロック記法」なるものを考えてみた』で紹介したものです。これは賛否両論なのでお好みに応じてお使い分けください。

一般的な設定

.zshrc
: "一般的な設定" && {
  autoload -U compinit && compinit # 補完機能の強化
  setopt correct # 入力しているコマンド名が間違っている場合にもしかして:を出す。
  setopt nobeep # ビープを鳴らさない
  setopt no_tify # バックグラウンドジョブが終了したらすぐに知らせる。
  unsetopt auto_menu # タブによるファイルの順番切り替えをしない
  setopt auto_pushd # cd -[tab]で過去のディレクトリにひとっ飛びできるようにする
  setopt auto_cd # ディレクトリ名を入力するだけでcdできるようにする
  setopt interactive_comments # コマンドラインでも # 以降をコメントと見なす
}

このへんはよく見かける設定ですね。個人的に気に入っているのはauto_cdです。最近$CDPATHを知って、これと組み合わせると大変便利だなと思う次第です。$CDPATHはどこにいてもcdできるディレクトリを指定できる環境変数です。例えば、次のような設定だと、どこにいても$HOME/projects/my-rails-appディレクトリにcd my-rails-appとやるだけで移動できます。

.zshenv
  cdpath=(
    $HOME/projects(N-/)
    $HOME/go/src/github.com/suin(N-/)
    $cdpath
  )

auto_cdはさらにcdコマンドまで省けるようにしてくれます。つまり、my-rails-appと叩くだけでcd ~/projects/my-rails-appが実行されるわけです。

ヒストリ関連の設定

.zshrc
: "ヒストリ関連の設定" && {
  HISTFILE=$HOME/.zsh_history # ヒストリファイル名
  HISTSIZE=10000 # メモリに保存される履歴の件数
  SAVEHIST=10000 # 履歴ファイルに保存される履歴の件数
  setopt hist_ignore_dups # 直前と同じコマンドをヒストリに追加しない
  setopt hist_ignore_all_dups # 重複するコマンドは古い法を削除する
  setopt share_history # 異なるウィンドウでコマンドヒストリを共有する
  setopt hist_no_store # historyコマンドは履歴に登録しない
  setopt hist_reduce_blanks # 余分な空白は詰めて記録
  setopt hist_verify # `!!`を実行したときにいきなり実行せずコマンドを見せる
}

ヒストリ周りは無頓着でしたが、fzfのあいまい検索と履歴を組み合わせるとCtrl+Rでサクッと検索できて便利だったので、ヒストリ周りを今回整備してみました。

この中では、share_historyが一番入れてよかったなと思います。タブを開きまくると、どのタブで実行したコマンドなのか忘れてしまっていたのですが、ヒストリを全タブで共有するようにしてから履歴を積極的に使うようになりました。

キーバインディング

zshrc
: "キーバインディング" && {
  bindkey -e # emacs キーマップを選択
  : "Ctrl-Yで上のディレクトリに移動できる" && {
    function cd-up { zle push-line && LBUFFER='builtin cd ..' && zle accept-line }
    zle -N cd-up
    bindkey "^Y" cd-up
  }
  : "Ctrl-Dでシェルからログアウトしない" && {
    setopt ignoreeof
  }
  : "Ctrl-Wでパスの文字列などをスラッシュ単位でdeleteできる" && {
    autoload -U select-word-style
    select-word-style bash
  }
  : "Ctrl-[で直前コマンドの単語を挿入できる" && {
    autoload -Uz smart-insert-last-word
    zstyle :insert-last-word match '*([[:alpha:]/\\]?|?[[:alpha:]/\\])*' # [a-zA-Z], /, \ のうち少なくとも1文字を含む長さ2以上の単語
    zle -N insert-last-word smart-insert-last-word
    bindkey '^[' insert-last-word
    # see http://qiita.com/mollifier/items/1a9126b2200bcbaf515f
  }
}

Ctrl-Yで上のディレクトリに移動できる」これは、cd ..を入力しないで済む設定。というか、cd ..にショートカットを割り当てる設定です。『ゼロから始める〜』でも似たような実装がありますが、今回はZLEをちゃんと駆使する実装にしてみました。

Ctrl-Wでパスの文字列などをスラッシュ単位でdeleteできる」の部分は読んでの通りなのですが、zshはデフォルトでスペース区切りしか単語を消せないので追加しました。パスを削るときに便利です。

Ctrl-[で直前コマンドの単語を挿入できる」は一つ前のコマンドの引数を持ってこれるようにしています。例えば、mkdir fooしたあとにcdとだけ入力してCtrl + [を押すと自動補完が効いてcd fooになります。実装は『zshで直前のコマンドラインの最後の単語を挿入する』をほぼそのまま参考にさせていただきました🙏🏻

略語展開(iab)

.zshrc
: "略語展開(iab)" && {
  abbrev-alias l="ls -laG" # G: macOSで色を付ける
  abbrev-alias la="ls -lahG"
  abbrev-alias l1="ls -1G"
  abbrev-alias tree="tree -NC" # N: 文字化け対策, C:色をつける
  abbrev-alias gpl="git pull"
  abbrev-alias gps="git push"
  abbrev-alias gco="git commit -av"
  abbrev-alias ga="git add -A"
  abbrev-alias gs="git status -s"
  abbrev-alias dp="docker ps"
  abbrev-alias di="docker images"
  abbrev-alias edi="eval \$(dinghy env)"
  abbrev-alias -g a1="awk '{print \$1}'"
  abbrev-alias -g a2="awk '{print \$2}'"
  abbrev-alias -g a3="awk '{print \$3}'"
  abbrev-alias -g a4="awk '{print \$4}'"
  abbrev-alias -g a5="awk '{print \$5}'"
  abbrev-alias -g a6="awk '{print \$6}'"
  abbrev-alias -g a7="awk '{print \$7}'"
  abbrev-alias -g a8="awk '{print \$8}'"
  abbrev-alias -g a9="awk '{print \$9}'"
  abbrev-alias -g a10="awk '{print \$10}'"
  abbrev-alias -g a11="awk '{print \$11}'"
  abbrev-alias -g a12="awk '{print \$12}'"
  abbrev-alias -g a13="awk '{print \$13}'"
  abbrev-alias -g a14="awk '{print \$14}'"
  abbrev-alias -g a15="awk '{print \$15}'"
  abbrev-alias -g a16="awk '{print \$16}'"
  abbrev-alias -g and="|" # パイプが遠いのでandを割り当てる。例えば`tail -f ./log | grep error`を`tail -f ./log and grep error`と書くことができる
}

本来「エイリアス」とされる部類ですが「略語展開」の設定として紹介します。というのも、aliasを強化したzsh-abbrev-aliasプラグインを使って、単純なエイリアスから展開までできるようにしているためです。どういうのかは動作を見てもらうとわかりますが、エイリアスをタイプした後にspaceキーを押すと、元のコマンドに展開されるという代物です。

今回試してみたのはパイプを略語展開にする設定です。グローバルエイリアスオプション(-g)を使って、「and」をパイプに割り当てています。明らかにパイプ(|)のほうがタイプ数は少ないですが、パイプキーがMacBook Proだと隅っこにあるのが難点でした。パイプが遠くてインラインでパイプ処理をあまりしたくない気持ちでしたが、andにしてみたところ、スムーズに打てるようになったので、パイプ処理を積極的に使うようになったと思います。

パイプの代わりにandをつかった処理
docker ps and grep http and awk '{print $1}'
tail -f /var/log/apache2/error.log and grep FATAL

エイリアスの内容は完全に僕の好みです。よく使うコマンドを短くしています。エイリアスの目的はタイプ数の削減ですが、自分で考えるのも面倒だなというのが最近の感想です😥 過去の傾向から自動でエイリアスを提案・生成してほしいなと。そういったツールってあるんでしょうか?

その他

.zshrc
: "cd先のディレクトリのファイル一覧を表示する" && {
  [ -z "$ENHANCD_ROOT" ] && function chpwd { tree -L 1 } # enhancdがない場合
  [ -z "$ENHANCD_ROOT" ] || export ENHANCD_HOOK_AFTER_CD="tree -L 1" # enhancdがあるときはそのHook機構を使う
}

: "sshコマンド補完を~/.ssh/configから行う" && {
  function _ssh { compadd `fgrep 'Host ' ~/.ssh/config.* | grep -v '*' |  awk '{print $2}' | sort` }
}

cd先のディレクトリのファイル一覧を表示する」はcdした後に移動先のディレクトリのファイルリストを自動で出す設定です。僕はcdした後にlsするのが癖になっていたので、これを自動化しました。人によっては全然不要だったりすると思います。

"sshコマンド補完を~/.ssh/configから行う」の設定は.ssh/configの設定からホスト名を補完する補完スクリプトを書いています。デフォルトの補完スクリプトは~/.ssh/known_hostsを見ているようで使い勝手が悪かったので自作しました。なお、configの設定はIncludeを使っています。これについては拙筆『待望の.ssh/configファイル分割がSSH 7.3から出来るようになったようです』をご覧ください。

RELATED POSTS