業務で使用している .zshrc 大公開!!! 〜〜ちょっとした解説付き〜〜

こんにちは!!!
広告事業本部でアプリケーションエンジニアをしている森田です!!

みなさん、Zsh使ってますか??
僕は昨年、新卒で入社したタイミングでbashから乗り換えて使い始めました。
業務でMacを使用するようになり、シェルを立ち上げるたびに「デフォルトZshやから乗り換えてな」的なメッセージが出てくるのが嫌で乗り換ることになりました...
きっかけとしてはこの通り受動的なものだったのですが、使ってみると意外と高機能でプラグインも豊富で以前よりよい開発体験を得ることができています。

乗り換えたてのころ、まわりの皆さんがどんな設定にしているのかなと気になり、
「ゾッシュってどんな設定にしてますか?」
と聞いたことがあり、場が一瞬???となったことがありました。
このブログではそんな僕がZshをズィーシェルと読むことを知り、業務のためにZshの設定ファイル.zshrcをいじってきた、その積み重ねの結果を共有させていただきます。

はじめに

このブログでは、新卒入社して約1年半の僕が実際に使用している.zshrcを恥ずかしながらも公開し、その後、軽い補足やお気に入りポイントの紹介をさせていただきます。
そもそもシェルとは何か?やZsh.zshrcとは何か?、Zshの便利なプラグインの話などはこのブログでは紹介いたしません。
なので、下記のような方々はこのブログの内容が参考になるかもしれません。

  • 業務でZshを使用している方
  • Zshのカスタマイズをしてみたい方

逆に下記のような方々にはこの記事の内容は合わないかもしれません。

  • シェル??Zsh??何それ??って方
  • fishしか勝たんみたいな方
  • Zshチョットワカル方

業務で使用している.zshrc大公開

早速ですが、僕が実際に業務で使用している.zshrcのブログ用を公開いたします。

# starship 有効化 ----------------------------------------------
eval "$(starship init zsh)"

# 補完機能有効化 ----------------------------------------------
autoload -Uz compinit
compinit

## 補完で小文字でも大文字にマッチさせる ===========================
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

## 補完候補を一覧表示したとき、Tabや矢印で選択できるようにする ===========================
zstyle ':completion:*:default' menu select=1

## sudo で補完有効化 ===========================
zstyle ':completion:*:sudo:*' command-path /usr/local/sbin /usr/local/bin \
                   /usr/sbin /usr/bin /sbin /bin /usr/X11R6/bin

# シンタックスハイライト有効化 ----------------------------------------------
source /opt/homebrew/opt/zsh-syntax-highlighting/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

# サジェスト有効化 ----------------------------------------------
source /opt/homebrew/opt/zsh-autosuggestions/share/zsh-autosuggestions/zsh-autosuggestions.zsh

# コマンド履歴検索 有効化 ----------------------------------------------
function peco-history-selection() {
  BUFFER=`history -n 1 | tac  | awk '!a[$0]++' | peco`
  CURSOR=$#BUFFER
  zle reset-prompt
}
zle -N peco-history-selection
bindkey '^H' peco-history-selection

## 履歴保存管理 ===========================
HISTFILE=$ZDOTDIR/.zsh-history
HISTSIZE=100000
SAVEHIST=1000000


# rbenv 有効化 ----------------------------------------------

export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init - zsh)"

# options ----------------------------------------------

setopt auto_cd

# alias ----------------------------------------------

## global ===========================

alias -g G='| grep'
alias -g H='| head'
alias -g L='| less'
alias -g C='| pbcopy'

## ls ===========================
alias ls='ls -G'
alias la='ls -a'
alias ll='ls -alF'

## cd ===========================
alias d='cd ~/dev'
alias ~='cd ~'
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'

alias prj='cd ~/dev/project_root'

alias playgorund='cd /Users/morita/local/playground'

## git ===========================
alias g='git'
alias ga='git add'
alias gc='git commit -m'
alias gac='git add . && git commit -m'
alias gca='git commit --amend'
alias gcan='git commit --amend --no-edit'
alias gcam='git commit --amend -m'
alias gr='git reset HEAD^'
alias gco='git checkout'
alias gs='git switch'
alias gs-='git switch -'
alias gl='git log --oneline'
alias gb='git branch'
alias gcp='git cherry-pick'
alias main='git switch main'
alias master='git switch master'

## docker ===========================
alias da='docker attach'
alias dc_='docker-compose'
alias dup_='docker-compose up'
alias de_='docker-compose exec'

alias dc='docker compose'
alias dup='docker compose up'
alias de='docker compose exec'

### container ===========================
#### rails
alias crspec='docker compose exec rails bin/rspec'
alias crs='docker compose exec rails bin/rspec $(git status -s "*_spec.rb" | cut -c4-)'
alias crubocop='docker compose exec rails bundle exec rubocop'
alias crb='docker compose exec rails bundle exec rubocop $(git status -s "*.rb" | cut -c4-)'
alias crba='docker compose exec rails bundle exec rubocop -a $(git status -s "*.rb" | cut -c4-)'
alias crbA='docker compose exec rails bundle exec rubocop -A $(git status -s "*.rb" | cut -c4-)'
alias cconsole='docker compose exec rails bin/rails c'
alias csandbox='docker compose exec rails bin/rails c --sandbox'
alias cc='docker compose exec rails bin/rails c'
alias crails='docker compose exec rails bin/rails'
alias cdb='docker compose exec rails bin/rails db'
alias cr='docker compose exec rails'
alias crsh='docker compose exec rails bash'
alias cspring='docker compose exec rails bin/spring'
alias css='docker compose exec rails bin/spring server'
alias csst='docker compose exec rails bin/spring stop'
#### react
alias cre='docker compose exec react'
alias cresh='docker compose exec react bash'
alias cnpm='docker compose exec react npm'
alias ccheck='docker compose exec react npm run check'
alias cfix='docker compose exec react npm run check:fix'
alias cbuild='docker compose exec react npm run build'
alias ctest='docker compose exec react npx vitest run'

## other ===========================
alias python='python3'
alias zshrc='code ~/.zshrc'
# alias ssh='~/zsh/ssh-iterm-setting'

# func

## ffmpeg

cgif () { # convert to gif
  local ext=${2:-mov}
  local r=${3:-10}

  ffmpeg -i $1.$ext -r $r $1.gif
}

## pbcopy

cwc () { # copy with command
  local res=$(eval $@);

  echo $res

  local all="${@}\n\n${res}"

  echo $all | pbcopy
}

## review

review () {
  local cnt=$(gh pr list --search "review-requested:@me" | wc -l)

  if [ $cnt -eq 0 ]; then
    echo "No review request"
  else
    gh pr list --search "review-requested:@me" -w
  fi
}

# 勝手に追加される系 ----------------------------------------------

### MANAGED BY RANCHER DESKTOP START (DO NOT EDIT)
export PATH="/Users/morita/.rd/bin:$PATH"
### MANAGED BY RANCHER DESKTOP END (DO NOT EDIT)

export PATH="/opt/homebrew/opt/mysql-client/bin:$PATH"
export PATH="/opt/homebrew/opt/curl/bin:$PATH"

# The next line updates PATH for the Google Cloud SDK.
if [ -f '/Users/morita/Downloads/google-cloud-sdk/path.zsh.inc' ]; then . '/Users/morita/Downloads/google-cloud-sdk/path.zsh.inc'; fi

# The next line enables shell command completion for gcloud.
if [ -f '/Users/morita/Downloads/google-cloud-sdk/completion.zsh.inc' ]; then . '/Users/morita/Downloads/google-cloud-sdk/completion.zsh.inc'; fi

解説

ここからは補足や、お気に入りポイントのお話をしていきます!!

setopt

.zshrcのsetoptでオプションをオンオフできるんですが、オプションの内容がman zshoptionsで確認できます!!

> man zshoptions
ZSHOPTIONS(1)          General Commands Manual      ZSHOPTIONS(1)

NAME
       zshoptions - zsh options

~~~

   Changing Directories
       AUTO_CD (-J)
          If a command is issued that can't be executed as a normal
        command, and the command is the name of a directory, perform the
        cd command to that directory.  This option is only applicable if
        the option SHIN_STDIN is set, i.e. if commands are being read
        from standard input.  The option is designed for interactive
        use; it is recommended that cd be used explicitly in scripts to
        avoid ambiguity.
~~~

調べても散文的で網羅的に確認する方法が分からず困っていましたが、社内向けChatGPTに聞いたところ教えてもらいました!!便利!!

エイリアス

ここからはエイリアスについてお話ししていきます!!

詳しい説明は省かせていただくのですが、エイリアスを設定することでショートカット的にコマンドを実行できます!!

例えばalias g='git'だと下記2コマンドが同等の挙動をします。

> git switch blog
> g switch blog

プロジェクトへのcd

alias prj='cd ~/dev/project_root'

この部分、お気に入りです!!
どのディレクトリにいてもすごく短いコマンドで目的のディレクトリに行けます!!

複数プロジェクトでいろんなディレクトリに行ったりするので満足度が高いです!!!!
設定も簡単でコスパもいいです。

コンテナ内でコマンド実行

### container ===========================
#### rails
alias crspec='docker compose exec rails bin/rspec'
~~~

このあたりですね、このコンテナ内でコマンド実行するエイリアスが一番使っているかもしれないです!!

現在関わっている全ての開発でDockerを使用しており、コンテナ内でコマンドを実行したいことがよくあります。
ですが、普段はホストでイケてるプロンプトのZshで作業しています。
コンテナ内のシェルがbashで何のカスタマイズもしていないので、コンテナ内のシェルに入るだけで なんかな〜 という気持ちになります。
だからといって毎回 docker compose exec container_name ~~をタイピングするのも長すぎて大変です。

そこで、よく使うコマンドをエイリアス設定することで、コンテナ内のシェルで打つコマンドと同じ長さ、むしろ短かったりする長さで実行できます!!
タイポも減るし、最高です。

↓↓↓イケてるプロンプトのZsh↓↓↓

コミットしていないファイルをリント、テスト

alias crb='docker compose exec rails bundle exec rubocop $(git status -s "*.rb" | cut -c4-)'

このgit status -s "*.rb" | cut -c4-の部分です!!
git status -s "*.拡張子"の部分でコミットしていない特定の拡張子のファイルをステータスを伴って取得しています。
cut -c4-でファイル名のみを抽出しています。
こうして得たファイル名の一覧をここではrubocopに渡して、リント、フォーマットしています。
一ファイルずつやるのはなかなか時間がかかるのでこれも重宝しています!!

ただ、削除したりリネームしたファイルも持ってきちゃうので、それでエラーになってしまいます。
伸び代ですね。

関数

ここからは.zshrcに定義している関数についてお話ししていきます!!

ここでも関数の詳細については省かせていただくのですが、.zshrcに関数を定義することでコマンドっぽく使うことができるようになります。

review () {
  local cnt=$(gh pr list --search "review-requested:@me" | wc -l)

  if [ $cnt -eq 0 ]; then
    echo "No review request"
  else
    gh pr list --search "review-requested:@me" -w
  fi
}

例えば上記のようにreview関数を定義すると、コマンドラインからreviewを実行できるようになります!!

> review
No review request

review関数

僕が所属する組織では、Findy Team+を用いた開発サイクルタイムの改善施策を進めています。
その中でレビューの優先度を意識的に上げようと考えたのですが、ブラウザを開いてGitHubを開いてレビュー依頼がきているPRを見つける流れが煩わしかったです。
レビュー依頼がきているPRのリストがサクッと開けたらいいのになぁーーと思って調べていました。
そこでghでいい感じにできそう、でも、レビュー依頼がない時もブラウザ開くの微妙やなというところに行きつきました。
そんな微妙やなを解決するのにちょっとした関数を.zshrcに定義するのがいいんです!!
これで僕のレビュー体験も上がるし、チームとしての開発サイクルの改善にもつながるので最高ですね!!

蛇足なんですが、↓のURLでレビュー依頼きてるPRの一覧を開くことはできます。
https://github.com/:organization/:repository/pulls?q=is%3Apr+is%3Aopen+reviewer%3A%40me
ただ、やっぱりターミナルで作業している時にブラウザに移動するのが煩わしいのと、ブラウザに移動して依頼がきていないときに微妙な気持ちになるのが嫌だったんですよね。

今後やりたいこと

ここまでいくつかお気に入りポイントを紹介させていただきました。
もっと紹介したいくらい、お気に入りポイントがいっぱいあります。
ですが、もっとよくなるやろ!!!!!!ってところもいっぱいあります。
ここではそんな伸び代を挙げておきます。

aliasをabbrにリプレイスしたい

aliasだとhistoryに省略した形で残ってしまうのですが、abbrを使用すると、実行時に省略形から実際のコマンドに展開されます!!
作業ログを共有したりする時に便利なんですが、シェルの立ち上げ時が微妙な感じなので試行錯誤中です...

カレントブランチと派生元ブランチ間で差分があるファイルを取得してリント、テストしたい

コミットしていないファイルをリント、テストの項で変更しているファイルをまとめてリントしている、とお話しさせていただきました。
実は色々妥協していて、本来は

  1. 派生元ブランチを自動取得
  2. 派生元ブランチとカレントブランチでのファイルの差分を取得
  3. まとめてリントする

が理想でした。
だったんですが、派生元ブランチの自動取得が難しくて妥協しちゃいました...
いつか理想の形に持っていきたい...

派生元ブランチさえ取得できたらファイルの一覧はgit diff --name-only $parent_branchで取得できるはず、なのでもう一歩な感じはあります。

差分があるファイルのテストファイルを抽出してテストしたい

前項とコミットしていないファイルをリント、テストの項に関わりがあるのですが、これはどちらも変更があったファイルのみを持ってきています。
ただ、これだとテストする時に、実はテストファイル変更し忘れてた!!をカバーできないです。
なので、変更があったプロダクトコードのファイルからテストコードファイルを特定して、それらをテストしたいんです!!
テストコードファイルの特定自体は、ファイルの命名規則がしっかりしていればsedなど使ってすぐにできるとは思います。
ただ、テストコードにすでに差分があったら?とかパターンを考えて実装まで行かないところで止まっちゃっています...
よくないですね!!!!

関数をファイル分割したい

.zshrcが肥大化してきているので、関数をファイル分割したいなと思ってます。
先ほども出てきた社内ChatGPTに教えてもらったところ、.zshrcファイル内でsource function_file.shすればいいみたいです!!
簡単そう!!でもディレクトリ構成どうしよ!!ってなってます。こんなんばっかですね。

おわりに

このブログでは恥ずかしながら僕が業務で使用している.zshrcを公開し、お気に入りポイントを紹介させていただきました。
Zshはプロンプトや拡張機能をいじるだけでも開発体験が爆増するのですが、一歩踏み込んでカスタマイズすることでより好みの使い心地になっていきますね。

本ブログを最後までお読みいただきありがとうございました!!