はじめに
セットアップ シリーズ、zsh 編。
構成
この記事では、以下について説明する。
- コマンドラインシェル: zsh(ズィーシェル)
- zsh 構成フレームワーク: Prezto(プレズト)
- zsh テーマ: Powerlevel10k
- フィルタリングツール: Peco
tmux は別記事にまとめたので、そちらを参照のこと。
環境
今回、検証に使った環境は以下のとおり。
OS | 端末エミューレーター | zsh |
---|---|---|
macOS 10.15 Catalina | ターミナル.app | zsh 5.8 (x86_64-apple-darwin19.3.0) |
Ubuntu 20.04 LTS on WSL 2 | Windows Terminal v1.5.10271.0 | zsh 5.8 (x86_64-ubuntu-linux-gnu) |
以下、「端末エミューレーター」(ターミナル)を「端末」と呼ぶ。
zsh について
macOS Catalina 以降(2019 年)で、macOS のデフォルトシェルが zsh に変更されたのは記憶に新しい。(経緯)
zsh は Bash の拡張版のような立ち位置で、ものすごい数の機能を持つ。
誕生は意外にも古く、Bash の翌年(1990 年)らしい。
fish について
zsh より現代的と言われる fish(2005 年 ~)は、POSIX シェル互換性が低いようなので、ひとまず採用を見送り中。
ショートカットキーの表記
本記事では、Emacs キーバインド風に、ショートカットを以下のように省略する。
-
C-
...Ctrl
キー /control
(⌃
)キー -
S-
...Shift
(⇧
)キー -
A-
...Alt
キー /option
(⌥
)キー -
D-
...command
(⌘
)キー- macOS のみ。
例えば、Ctrl + Shift + Alt + a
なら、C-S-A-a
と表記する。
また、連続して入力する場合は「スペース」を使う。
例えば Ctrl + X
の直後に Y
を入力なら、C-X Y
と表記する。
👑 コマンドラインシェル: zsh(ズィーシェル)
zsh のインストール
確認:
zsh
が未インストール、または、バージョンが古ければ、最新版の zsh
をインストールする。
$ which zsh && zsh --version
macOS でのインストール:
デフォルトの zsh は古いので、Homebrew で最新版をインストールする。
$ brew install zsh
Ubuntu でのインストール:
$ sudo apt install zsh
適用:
# 確認
$ which zsh && zsh --version
/usr/bin/zsh
zsh 5.8 (x86_64-ubuntu-linux-gnu)
# ログインシェルの選択候補に、インストールした zsh が登録済みか確認
$ grep "$(which zsh)" /etc/shells
# 上記の結果 /etc/shells になければ、zsh のパス(which zsh の結果)を追記しておく。
## e.g.
## $ sudo sh -c "echo '$(which zsh)' >> /etc/shells"
# ログインシェルを zsh に変更
$ chsh --shell "$(which zsh)"
# 端末を再起動
# 確認
$ echo $SHELL
/usr/bin/zsh
zsh の設定
最終的な本記事による ~/.zshrc
の内容は以下のとおり。
# Executes commands at the start of an interactive session.
# ================================
# Loading file
# ================================
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
# Executes commands at the start of an interactive session.
# Initialization code that may require console input (password prompts, [y/n]
# confirmations, etc.) must go above this block; everything else may go below.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
# Source Prezto.
if [[ -s "${ZDOTDIR:-$HOME}/.zprezto/init.zsh" ]]; then
source "${ZDOTDIR:-$HOME}/.zprezto/init.zsh"
fi
# ================================
# Loading zsh function
# ================================
# Enable compinit.
autoload -Uz compinit
compinit
# Enable powerlevel10k.
autoload -Uz promptinit
promptinit
prompt powerlevel10k
# Enable cdr.
# cf. http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#index-cdr
autoload -Uz chpwd_recent_dirs cdr add-zsh-hook
add-zsh-hook chpwd chpwd_recent_dirs
zstyle ':completion:*:*:cdr:*:*' menu selection
zstyle ':completion:*' recent-dirs-insert both
zstyle ':chpwd:*' recent-dirs-max 500
zstyle ':chpwd:*' recent-dirs-default true
zstyle ':chpwd:*' recent-dirs-file "${XDG_CACHE_HOME:-$HOME/.cache}/shell/chpwd-recent-dirs"
zstyle ':chpwd:*' recent-dirs-pushd true
# Enable zmv
autoload -Uz zmv
# ================================
# Other zsh settings
# ================================
# ignore C-D logout
setopt IGNOREEOF
# silent
setopt no_beep
# Set ls colors
if [[ -f ~/.dircolors && $(which dircolors) ]]; then
eval $(dircolors -b ~/.dircolors)
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
fi
# ================================
# Keybinds
# ================================
# C-U: Same as Bash
## Change before: kill-whole-line
bindkey \^U backward-kill-line
# C-R: peco-history-selection
## Change before: history-incremental-search-backward
function peco-history-selection {
BUFFER=$(\history -nr 1 | peco)
CURSOR=${#BUFFER}
}
zle -N peco-history-selection
bindkey \^R peco-history-selection
# C-S: peco-cdr-selection
## Change before: history-incremental-search-forward
function peco-cdr-selection {
BUFFER="cd $(cdr -l | awk '{ print $2 }' | peco)"
CURSOR=${#BUFFER}
}
zle -N peco-cdr-selection
bindkey \^S peco-cdr-selection
# ================================
# Aliases
# ================================
# use alias with sudo
# cf. https://manpages.debian.org/bullseye/manpages-ja/bash.1.ja.html#alias~2
alias sudo='sudo '
# -i ... force pre-execution confirmation
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'
# -l ... long listing
# -a ... list entries starting with .
# -F ... append file type indicators for /
# -h ... print sizes in human readable form
alias ll='ls -laFh'
# -n ... suppress line numbers
# -i ... yyyy-mm-dd format time-stamps
# -D ... print elapsed times
alias history='history -niD'
# -a ... print all occurrences in path
alias which='which -a'
# noglob ... Do not expand meta characters.
# -W ... Use wildcards without parentheses
alias zmv='noglob zmv -W'
# Show clock
## If you don't want to stop the SSH session.
alias showclock='watch -n 60 date'
# psql tsv output
# SHOULD TEST ME
alias psqltsv='psql -AF $'\''\t'\'''
# ================================
# Environment variables
# ================================
# Date and time format
## longer: YYYY-MM-DD W hh:mm:ss Z
### export TIME_STYLE='+%F %a %T %Z'
## middle: YYYY-MM-DD hh:mm:ss
export TIME_STYLE='+%F %T'
## shorter: MM-DD hh:mm
### export TIME_STYLE='+%m-%d %H:%M'
# Overwrite .zprofile (Prezto)
export EDITOR='vim'
export VISUAL='vim'
# less
## -i ... ignore case in searches that lack uppercase
## -R ... display control chars; keep track of screen effects
## -W ... highlight first unread line after forward movement
## (-S ... truncate long lines instead of folding)
export LESS='-iRW'
(補足)zsh キーバインドについて
- キーバインドの空きを探す:
-
Esc
の代替キーバインド:C-[
👑 zsh 構成フレームワーク: Prezto(プレズト)
- zsh を適切なデフォルト、エイリアス、関数、補完、プロンプトテーマで強化する。
- oh-my-zsh より高速らしいので採用。
注意:
-
~/.zshrc
が存在しないことを確認しておくこと。
(上書きされるので、必要なら退避すること)
インストール:
# 公式の手順に従って prezto をインストール & 構成ファイルを配置
$ git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"
$ setopt EXTENDED_GLOB
for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do
ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}"
done
# ~/ 配下に .zlogin, .zlogout, .zpreztorc, .zprofile, .zshenv, .zshrc が生成される
# 端末を再度起動
# プロンプトが ❯❯❯ に変更されていることを確認
# デフォルトのエディターが `nano` なので、好みに応じて `vi` や `vim` などに変更
## ここで定義されているので
$ grep nano ~/.zprofile
export EDITOR='nano'
export VISUAL='nano'
## ~/.zshrc の末尾に追記する
$ vi ~/.zshrc
export EDITOR='vi'
export VISUAL='vi'
# 反映
$ . ~/.zshrc
## 確認
$ grep vi ~/.zshrc
export EDITOR='vi'
export VISUAL='vi'
主な設定確認 - 環境変数:
- history の保存先は
~/.zhistory
になっている。
echo $HISTFILE
主な設定確認 - zsh オプション:
cf. zsh: 16 Options
- history にタイムスタンプを付与する
EXTENDED_HISTORY
(extendedhistory
) などが有効になっている。
$ setopt | grep hist
extendedhistory
histexpiredupsfirst
histfindnodups
histignorealldups
histignoredups
histignorespace
histsavenodups
histverify
sharehistory
-
cd
なしで、パスだけ打ち込むとディレクトリーを移動できる。
$ setopt | grep autocd
autocd
アップデート:
cd $ZPREZTODIR && git pull && git submodule update --init --recursive
👑 zsh テーマ: Powerlevel10k
zsh の配色(プロンプトテーマ)を構成してくれるツール。
注意:
- 事前に Nerd Fonts(アイコンのフォント)を含むフォントをインストールし、端末のフォントに設定しておくこと。
- 今回は日本語フォントを含む HackGenNerd Console を採用。
(Regular、Bold、Italic、Bold Italic がすべて利用可能か確認しておくこと)
インストール:
# zsh のテーマ一覧で、powerlevel10k が既に選択可能なことを確認
$ prompt -l | grep powerlevel10k
# zsh のテーマとして powerlevel10k を選択
$ prompt -s powerlevel10k
## 対話式コマンドで、表示が正しいか確認される
## フォントが正しくインストール & 設定されていれば、すべて NO の選択肢になるはず
## その後、引き続き対話式コマンドで、好みのテーマを作成できる
## 対話式コマンドが終了すると、選択内容に応じたテーマに変更される
# 上記コマンド後の表示されるメッセージに従い、.zshrc の末尾に以下を追記
## 追記するまで、選択したテーマは保存されない
$ vi ~/.zshrc
autoload -Uz promptinit
promptinit
prompt powerlevel10k
# 反映
$ . ~/.zshrc
👑 フィルタリングツール: Peco
cf. peco を使ったらターミナルの操作が劇的に効率化できた話 - Qiita
cf. peco を使って端末操作を爆速にする - Qiita
cf. Sample Usage · peco/peco Wiki
コマンドの実行履歴などを、非常に便利に検索できるツール。
今回は、Peco を使うためのラッパー関数には anyframe などは使わず、手直しの簡便さを優先して .zshrc
に直接記載する。
macOS:
brew install peco
Ubuntu:
sudo apt install peco
手順:
# 確認
$ peco --version
peco version v0.5.1
# 以下を追記
## C-R でコマンド履歴を呼び出せるように。
## C-S キーで今まで移動したことのあるディレクトリーへ移動できるように。
$ vi ~/.zshrc
# Enable compinit.
autoload -Uz compinit
compinit
# Enable cdr.
# cf. http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#index-cdr
autoload -Uz chpwd_recent_dirs cdr add-zsh-hook
add-zsh-hook chpwd chpwd_recent_dirs
zstyle ':completion:*:*:cdr:*:*' menu selection
zstyle ':completion:*' recent-dirs-insert both
zstyle ':chpwd:*' recent-dirs-max 500
zstyle ':chpwd:*' recent-dirs-default true
zstyle ':chpwd:*' recent-dirs-file "${XDG_CACHE_HOME:-$HOME/.cache}/shell/chpwd-recent-dirs"
zstyle ':chpwd:*' recent-dirs-pushd true
# C-R: peco-history-selection
function peco-history-selection {
BUFFER=$(\history -nr 1 | peco)
CURSOR=${#BUFFER}
zle reset-prompt
}
zle -N peco-history-selection
bindkey \^R peco-history-selection
# C-S: peco-cdr-selection
function peco-cdr-selection {
BUFFER="cd $(cdr -l | awk '{ print $2 }' | peco)"
CURSOR=${#BUFFER}
zle reset-prompt
}
zle -N peco-cdr-selection
bindkey \^S peco-cdr-selection
# 反映
$ . ~/.zshrc
補足:
- 端末起動時にエラーが出る場合は、
~/.zshrc
の zsh 組み込み関数compinit
を見直すべきことが多い。詳細は以下の記事が詳しい。 - よくお勧めされる zsh-completions は不要と思われる。
- 少なくとも導入前後で
~/.zcompdump
の内容は、ほとんど変わらなかった。
- 少なくとも導入前後で
入力補完の強化
brew 補完
Homebrew Shell Completion — Homebrew Documentation
heroku 補完
Heroku CLI 用の zsh 設定は不要だった件 / マスタカの ChangeLog メモ
heroku autocomplete --refresh-cache
docker 補完
Command-line completion | Docker Documentation
etc=/Applications/Docker.app/Contents/Resources/etc
ln -s $etc/docker.zsh-completion /usr/local/share/zsh/site-functions/_docker
ln -s $etc/docker-compose.zsh-completion /usr/local/share/zsh/site-functions/_docker-compose
$ https://github.com/docker/docker/blob/master/contrib/completion/zsh/_docker
$ https://github.com/docker/compose/blob/master/contrib/completion/zsh/_docker-compose
$ curl -L https://raw.githubusercontent.com/docker/compose/1.27.4/contrib/completion/zsh/_docker-compose \
> ~/.zsh/completion/_docker-compose
$ exec $SHELL -l
🔧 zsh の細かな設定
ls コマンドの色変更
GNU 版 ls コマンド用の色が見づらかったので、修正。
(一部の「背景色」と「文字色」が同系色で見づらい)
注意:
この手順は macOS のデフォルトである BSD 版 ls コマンド 用ではない点に注意。
手順:
dircolors コマンド で、デフォルトのカラー構成情報をコピーして使う。
設定可能な色は ISO 6429 (ANSI) カラーシーケンス を参照。
# デフォルトのファイルをコピー
$ dircolors -p > ~/.dircolors
# 以下のように変更(文字色を黒に、黒字に合わない背景色を変更)
$ vi ~/.dircolors
- OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky
+ OTHER_WRITABLE 30;46 # dir that is other-writable (o+w) and not sticky
- STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable
+ STICKY 30;44 # dir with the sticky bit set (+t) and not other-writable
# 以下を追記して、ls コマンドの配色と、zsh のファイル名補完の配色を変更
$ vi ~/.zshrc
eval $(dircolors -b ~/.dircolors)
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
# 反映
$ . ~/.zshrc
ちなみに eval
を使っているのは、単に dircolors -b <path>
の出力結果が LS_COLORS=<色情報>
なので、そのまま式を評価すれば環境変数 LS_COLORS
に代入できるため。
また ${(s.:.)LS_COLORS}
の変数展開は、zsh の Parameter Expansion Flags の s
フラグを使った split を使っている。
zmv コマンドの有効化
zsh 組み込みコマンド zmv
は、ファイル名を一括リネームできる。
有効化の手順:
# 以下を追記
$ vi ~/.zshrc
# Enable zmv
autoload -Uz zmv
# noglob ... Do not expand meta characters.
# -W ... Use wildcards without parentheses
alias zmv='noglob zmv -W'
# 反映
$ . ~/.zshrc
使い方:
以下のように、一括リーネームできる。
# 確認用に、任意のファイルを用意する。
$ cd <任意のフォルダー>
$ touch foo.txt bar.txt baz.txt
# リネームを実行せず、結果を事前に確認する
$ zmv -n *.txt *.csv
mv -- bar.txt bar.csv
mv -- baz.txt baz.csv
mv -- foo.txt foo.csv
# リネームを実行
$ zmv *.txt *.csv
主なオプション:
-
-n
: リネームを実行せず、結果を事前に確認する。 -
-C
: 移動ではなく、コピーする -
-f
: ファイルが存在しても上書きする
その他:
-
変数展開や算術式を活用して、ファイル名に連番を付与することもできる。
- ただし、今回は
.zshrc
の alias で定義しているnoglob
によって式の挙動が変わるため、コマンド名に\
を付けて alias をエスケープ(無視)する必要がある。 - e.g.
c=1 \zmv -n '(*).txt' '${1}-$((c++)).txt'
- ただし、今回は
付録: zsh に関する細かいこと
その他の zsh の機能
- GNU Redline キーバインド互換
- Bash などと同じく、emacs に似たキーバインドで行を操作できる。
- ちなみに、zsh のキーバインドは
readline
ではなく、独自の zsh 組み込みコマンドzle
(Zsh Line Editor)を使っている。
- buffer stack(コマンドラインスタック)
-
zle
の機能により、入力中のコマンドをスタックに退避できる。
使いたい場面に出くわしていないが、一応掲載しておく。 - cf. 「漢の zsh」で取り上げてほしいネタ案 @ val it: α → α = fun
-
zsh の設定でよく使うコマンド
細かい調整のために。
-
setopt
コマンド- zsh のシェルとしてのオプションを設定する zsh 組み込みコマンド。
- 引数を指定しない場合、オプション一覧を表示する。
オプション名は、なぜか区切り文字のない小文字のみで、大変読み辛い。
-
autoload
コマンド- 環境変数
FPATH
やfpath
で指定されたファイル内のシェル関数を、その関数の初回実行時に自動的に読み込み、関数を使えるようにするための zsh 組み込みコマンド。 - cf. 9.1 Autoloading Functions - zsh: 9 Functions
- 環境変数
-
zstyle
コマンド- 補完機能(Completion System)などを操作する zsh 組み込みコマンド。
- zsh にはスタイルとタグという概念があり、補完機能ならタグは補完対象が何であるかを示し、スタイルはそれをどのように補完するかを示す。
- cf. zstyle - 22.37 The zsh/zutil Module - zsh_ 22 Zsh Modules
- cf. zsh: 20 Completion System
ログインシェルとインタラクティブシェル
cf. 2.1: Types of shell: interactive and login shells - A User's Guide to the Z-Shell
zsh 特有の話ではないが、「ログインシェルか?」や「インタラクティブシェルか?」は、気にし出すとややこしい。
例えば、Ubuntu Desktop の「GNOME 端末」など、GUI の端末からシェルを起動する場合は、ログインシェルではない。
ただし、macOS は GUI だが、「ターミナル.app」(デフォルト端末)や、「iTerm2.app」はログインシェルとして起動する。
また、ssh
コマンドで ssh user@remote-host /path/command
のようにコマンドを実行する場合は、インタラクティブシェルではない。
確認手順:
# ログインシェルか?
$ [[ -o login ]] && echo true || echo false
# インタラクティブシェルか?
$ [[ -o interactive ]] && echo true || echo false
上記では、シェルオプションに login や interactive を含むか評価している。
シェルオプションの一覧は、前述のとおり引数なしの setopt
コマンドで確認できる。
なお、shopt
コマンドは Bash の組み込みコマンドなので、zsh では使えない。
zsh の設定ファイル
cf. zsh: 5 Files
cf. Zsh/Bash startup files loading order (.bashrc, .zshrc etc.) | The Lumber Room
基本的に ~/.zshrc
さえ覚えておけば OK。
設定は下表の上から順番に読み込まれる。
この時、各ファイルはそれぞれグローバル設定(/etc/
配下)、ローカル設定(~/
配下)の順に読み込まれる。
ファイル名 | ログイン シェル |
インタラクティブ シェル |
シェル スクリプト |
用途 |
---|---|---|---|---|
.zshenv |
🔵 | 🔵 | 🔵 | 起動時に必ず読み込まれる。 |
.zprofile |
🔵 | ❌ | ❌ | ログイン時にのみ、.zshrc より前に読み込まれる。 |
.zshrc |
🔵 | 🔵 | ❌ | 👑 メイン設定ファイル。 |
.zlogin |
🔵 | ❌ | ❌ | ログイン時にのみ、.zshrc より後に読み込まれる。 |
.zlogout |
🔵 | ❌ | ❌ | ログアウト時(exit / logout )にのみ読み込まれる。 |
補足:
- グローバル設定のファイル名は、
.
を含まない。- e.g.
/etc/zshenv
- e.g.
- ローカル設定は、環境変数
ZDOTDIR
が定義されていればこちらを優先する。
未定義の場合のみ、環境変数HOME
=~
のパス配下を参照する。
付録: Bash との挙動の主な違い
-
history
コマンド- デフォルトだと直近 16 件しか表示されない。すべて表示するには
history 1
。 - 履歴を削除したい場合は
vi $HISTFILE
などで編集する。
- デフォルトだと直近 16 件しか表示されない。すべて表示するには
- 単語区切り
- 単語区切りのための環境変数
WORDCHARS
のせい(?)
- 単語区切りのための環境変数