9
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

セットアップ - zsh

Last updated at Posted at 2021-05-09

はじめに

セットアップ シリーズ、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 キーバインドについて

👑 zsh 構成フレームワーク: Prezto(プレズト)

注意:

  • ~/.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

アップデート:

cf. https://github.com/sorin-ionescu/prezto#updating

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 Flagss フラグを使った split を使っている。

zmv コマンドの有効化

cf. zmv - zsh: 26 User Contributions

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 の機能

zsh の設定でよく使うコマンド

細かい調整のために。

ログインシェルとインタラクティブシェル

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
  • ローカル設定は、環境変数 ZDOTDIR が定義されていればこちらを優先する。
    未定義の場合のみ、環境変数 HOME = ~ のパス配下を参照する。

付録: Bash との挙動の主な違い

  • history コマンド
  • 単語区切り
    • 単語区切りのための環境変数 WORDCHARS のせい(?)

参考文献

9
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?