長いこと Bash を使い続けていました。 逆張り癖が災いしすぎた気がします。 Bash は man ページを一通り読むくらいには愛着を持っていたり、あれこれ触ったりしていました。
Zsh の導入自体は何度か挑戦しようとしていたのですが、(多くは勉強不足で)合わなさを感じてしまって投げ出していました。 先日ふと思い立ってまた触り始めてみて、挫折しないようにちゃんと調べながら触っていたところ、かなり快適になったのでメモしておきます。
導入
brew install zsh
とかをしたと思います。Mac 以外の人はよしなに。
カスタム
こんな感じになりました。
シェルをカスタマイズするとき、何から始めますか? えびちゃんは PS1
から始めます。
PS1
PS1
は、コマンドを入力する際の >
的な部分に表示させる文字列(prompt string)の一つです。
あんまりごちゃっとはさせたくないんですが、必要最低限のものは書かれていてほしいです。
- 前の処理との間の空行*1
- 前の処理の終了ステータス
- シェルのバージョン情報と
SHLVL
- これはいらないかも
SHLVL
はシェル中でシェルを起動すると増えるやつです
- 停止中のジョブ数
- カレントディレクトリ
かなりすごくて、大抵は ここ を見ると解決します。 条件分岐とか、太字や色などのハイライトも揃ってます。
終了ステータスは、こんな感じで表示させるやつです。
- 値によって異なる文字列を出力したい
- コマンドを入力しなかった場合は表示されないでほしい
という要望がえびちゃんの中ではあります。
毎回表示されてよくて、せいぜい色分けだけしてくれればいいというのであれば、次のような感じに書けばいいです。
PS1='%(?.%F{10}0%f.%F{9}%?%f)%# '
えーすごいね。
0 じゃなかったときだけ表示してくれればいいのなら、オプションで済むようです。
setopt print_exit_value
えびちゃんの設定については、記事を書きました。
シェルオプション
setopt interactive_comments # 対話モードでも # をコメントにする setopt correct # 訂正をお願いする unsetopt correct_all # お節介すぎるのはやめてほしい setopt noautomenu # 補完が一意じゃなかったら怒ってね setopt histverify # 履歴の展開は実行前に確認してね setopt extended_history # 履歴をいい感じに書いてね setopt magic_equal_subst # 補完をうまくやってね
magic_equal_subst
、すごくて、
make --prefix=/path/to/
みたいなののパスも補完してくれます。
環境変数
export WORDCHARS='' # 単語とみなす英数字以外の文字集合 export FIGNORE='~' # 補完の際に無視する接尾辞 export HISTSIZE=100000 # 履歴に関するものたち export SAVEHIST=100000 export HISTFILE=$HOME/.zhistory
キーバインド
以下では、よくある略記を使います。
^X^Y
orC-x C-y
- control を押しながら
x
を押して、control を押しながらy
を押す
- control を押しながら
^Xz
orC-xz
- control を押しながら
x
を押して、control を離してz
を押す
- control を押しながら
^[w
or\ew
orM-w
- esc を押したあと
w
を押す - option (meta, alt) を押しながら
w
を押す
- esc を押したあと
control と同時押しされる文字は case-insensitive*2 ですが、option と同時押しの場合は case-sensitive っぽい挙動をするので気をつけましょう。
emacs-forward-word
デフォルトの M-f
が emacs のように「単語の末尾へ移動」ではなくて「次の単語の頭へ移動」だったのが気に食わなかったので変えました。
bindkey '^[f' emacs-forward-word
option を押しながら「→」を押したときの挙動も変わります。
^[F
と入力すると option+shift+f
になるので注意しましょう。
pound-insert
M-#
で、その行をコメントだったことにできます。
bindkey '^[#' pound-insert
expand-or-complete-prefix
cd Doc/neko
のように書いてから、Doc
の後にカーソルを持っていって TAB
を押したとき、Doc.../neko
のように補完されてほしいです。
デフォルトだと Doc/neko...
のような補完をしてしまうらしいので、変えます。
bindkey '^I' expand-or-complete-prefix
digit-argument
emacs や bash では、キーバインドを実行する際に引数を渡すことができます。
たとえば、a
に 20 を渡すと 20 個の a
を挿入できたりします。
挿入の方法としては、次のいずれかがあります。
M-2 0 a
M-2 M-0 a
C-u 20 a
C-u 20 C-u a
a
ではなく1
のような数字に引数を渡したい場合はC-u
で引数部分の終了を示す- 数字以外なら任意
zsh では若干挙動が違っていて、M-2 0
と入力すると、0
に 2 を渡したことになるっぽいですね。
M-2 M-0 a
のように渡す必要があるようです。
それから、入力中の引数が表示されてくれなくて不便だったので、自分で少し書いてみることにしました。
実装が長めなのでこれも後でどうにかするとして、デモだけ貼ります。
Zsh、デフォルトの数値引数のキーバインドが表示されてくれなくて不満だったので、練習がてらつくってみたよ pic.twitter.com/0iW2OsuV0x
— えびちゃん (@rsk0315_h4x) 2020年5月21日
いつもの
いくつかのキーバインドは、Zsh 以外のキーバインドと衝突して、思うように使えないのです。 それを無効化してしまいます。
stty start undef # '^q' stty rprnt undef # '^r' stty stop undef # '^s' stty kill undef # '^u' stty werase undef # '^w'
元通りに戻したいときは、undef
の箇所を ^q
などに置き換えたものを実行するとよいです。
その行を消してからターミナルを再起動してもいいと思います。
さて、自分のすきなのを割り当てます。
bindkey '^W' kill-region
ハイライト
これの存在を忘れていました。ここ に従います。
for k in ${(k)ZSH_HIGHLIGHT_STYLES}; do echo "ZSH_HIGHLIGHT_STYLE[$k]='${ZSH_HIGHLIGHT_STYLES[$k]}'"; done
などを実行すると、指定できる箇所がわかるので、適宜書き換えて実行します。
ZSH_HIGHLIGHT_STYLES[double-hyphen-option]='fg=#7F7F7F' ZSH_HIGHLIGHT_STYLES[globbing]='fg=magenta' ZSH_HIGHLIGHT_STYLES[single-hyphen-option]='fg=#7F7F7F' ZSH_HIGHLIGHT_STYLES[arg0]='fg=white,bold' ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=9' ZSH_HIGHLIGHT_STYLES[comment]='fg=#7F7F7F' ZSH_HIGHLIGHT_STYLES[path]='none'
オプションのハイライトって実質不可能で、文字列からだけでは -bar
が -b
に ar
を渡したのか、-b -a -r
と等価なやつなのかわからないんですけどね。-b ar
と -bar
が等価な場合とそうじゃない場合があったり。
ところで本来 --
以降はオプションと見なされないんですが、これもオプションとして色がついちゃいます。むむー。
補完
partial-word completion
emacs のファイル名補完って便利で、
foo/bar-baz
foo/bad
food/basket
failed/bag
fish/big-neko
のようなファイルたちがあったとき、f/-n
と入力してから TAB
を押すと fish/big-neko
に補完してくれたりするんですよね。
というのを、Zsh にもやってもらいます。
autoload -Uz compinit
compinit
対話モードで compinstall
を実行して、2. Matching control
を選ぶと出てくる p. Partial-word completion
がそれっぽいんですが、それをしなくてもやってくれそう? ちょっとよくわからないです。
zstyle ':completion:*' matcher-list 'r:|[._-]=** r:|/=* r:|=*' autoload -Uz compinit compinit
こんな感じのを書くとよかったです。 a-b-c
のようなファイル名に対しては -<TAB>
で補完が効くのですが、ディレクトリに関してはそういう補完をしてほしくないので、/
は *
にしています。
詳しくは ここ を読むといいです。
不満
ところで */-n
とかだと補完されてくれません。ワイルドカードが混ざってると無理ってどこかで見たような気もします。
.//-n
とかで補完するといいのかも。
単語の途中で補完した場合(上の補完の例で f/b
と書いて TAB
を押した場合などに発生する)に /
が付加されないでほしくて、そういうオプションはあってほしいのですが、見つからないですね。
squeeze-slashes
はちょっと違う気がします。squeeze されてほしくないときもあるので。
と思ったんですが、補完される /
を無視して移動すると無くなってくれるので、とりあえずは我慢かなぁ。
git
の補完
なんか手元で補完して出てくるのとサンプルが違ったので困ってました。
これ を ~/.zsh/completions/_git
とかに置いておいて、
fpath=(~/.zsh/completions/_git $fpath)
とかするとよさそう。
ZLE
Zsh command line editor と呼ばれるやつです。
キーバインドで呼ばれる関数(ウィジェットとか呼ばれてそう)を自分で作ったり、キーを割り当てたりできます。
neko() { # したい処理を書く # zle -R '> ' みたいにプロンプトを書けたり # "$BUFFER" で行の内容を取れたり # zle -U "$key" みたいにして return 後に $key を入力したことにできたり # いろいろできる }
サンプルは ここ とか見るといいかも。
関数を作ったら、キーバインドも設定します。
zle -N neko && bindkey '^Xneko' neko
SPROMPT
correct が関連してるんですが、間違ったコマンドを入力すると訂正してくれます。 そのときのメッセージもカスタマイズできます。
export SPROMPT='zsh: correct '\''%B%R%b'\'' to '\''%B%r%b'\'' ([n]/y/a/e)? '
これができるなら bck-i-search
とか fwd-i-search
の文字列も変更させてくれてもよくない? 変に略されてるのすきじゃないんですが...
ハードコードされているように見えるなぁ。
PROMPT_EOL_MARK
(デフォルトでそうなんですが)prompt_cr
と prompt_sp
が有効になっていると
echo -n neko
のような、改行で終わらないコマンドを実行すると末尾に %
が付加されます。
この %
を設定する変数です。デフォルトでは %F%S%#%s%f
のようなのと等価だと思います。
おわり
ほぼ不満がなくなったのでこの辺でひとまず終わり。
*1:前の処理の末尾に改行がなかったら適当なマーカーがつくっぽい?
*2:大文字か小文字かを気にしない。case-sensitive は気にする。