僕のzsh環境2021夏 〜Forever Love〜

僕は普段の開発ではzshを利用しており、先日PC移行した際に、あれこれ整備し直したので紹介します。

setup.sh

絶対に使うソフトウェアがどの環境でも入るようにしている。基本バージョンは固定せずに、最新が最高と思っています。

#!/bin/zsh
SCRIPT_DIR=$(cd $(dirname $0); pwd)
RUBY_VERSION=2.7.2
GO_VERSION=1.15.7

which brew > /dev/null || /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
test -e /usr/local/opt/kube-ps1/share/kube-ps1.sh || (brew install kube-ps1 && source "/usr/local/opt/kube-ps1/share/kube-ps1.sh")
test -e ${HOME}/.oh-my-zsh/oh-my-zsh.sh || sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
which openstack > /dev/null || (curl -s https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3 get-pip.py && pip install python-openstackclient)

# brew
ARRAY=(vim tmux pt peco reattach-to-user-namespace ghq tfenv consul-template tig stern jq gsed sshuttle)
for item in ${ARRAY[@]}; do
  which $item > /dev/null|| brew install $item
done

# envs
which anyenv > /dev/null || (brew install anyenv && eval "$(anyenv init -)" && anyenv install --init && \
  mkdir -p $(anyenv root)/plugins && git clone https://github.com/znz/anyenv-update.git $(anyenv root)/plugins/anyenv-update)

ARRAY=(rbenv phpenv goenv)
for item in ${ARRAY[@]}; do
  test -e ~/.anyenv/envs/$item || (anyenv install $item)
done

# ruby
ruby -v | grep ${RUBY_VERSION} > /dev/null || rbenv install ${RUBY_VERSION} && rbenv global ${RUBY_VERSION}

# go
go version | grep ${GO_VERSION} > /dev/null || goenv install ${GO_VERSION} && goenv global ${GO_VERSION}

# configs(この辺はお好みで)
ARRAY=(tigrc tmux.conf vimrc zshrc gitconfig rubocop.yml clang-format)
for item in ${ARRAY[@]}; do
  ln -sf $SCRIPT_DIR/_$item ~/.$item
done

.zshrc

環境変数は.zshenvにまとめるようにして、端末が変わっても普遍で動いてほしい設定を.zshrcにまとめています。

なんか全部のせてもあれなんで便利機能だけ。

history

historyは Ctrl + r と押すとpecoを利用して過去の履歴からペロッと貼れるようにしています。もはやこれがないと生産性が4くらいになります。

# historyを共有する
HISTFILE=~/.zsh_history
HISTSIZE=100000
SAVEHIST=100000
setopt hist_ignore_dups     # ignore duplication command history list
function peco-select-history() {
    local tac
    if which tac > /dev/null; then
        tac="tac"
    else
        tac="tail -r"
    fi
    BUFFER=$(\history -n 1 | \
        eval $tac | \
        peco --query "$LBUFFER")
    CURSOR=$#BUFFER
    zle clear-screen
}

zle -N peco-select-history
bindkey '^r' peco-select-history

ターミナル表示

vcs_infoを利用して、ブランチの状態やkubernetesクラスタの情報を表示している。あまり長いのは好みではないから必要な情報だけ。

autoload -U promptinit; promptinit
autoload -Uz colors; colors
autoload -Uz vcs_info
autoload -Uz is-at-least

# begin VCS
zstyle ":vcs_info:*" enable git
zstyle ":vcs_info:*" formats "(%s)-[%b]"
zstyle ":vcs_info:*" actionformats "(%s)-[%b|%a]"
zstyle ":vcs_info:(svn|bzr):*" branchformat "%b:r%r"
zstyle ":vcs_info:bzr:*" use-simple true

zstyle ":vcs_info:*" max-exports 6

if is-at-least 4.3.10; then
    zstyle ":vcs_info:git:*" check-for-changes true # commitしていないのをチェック
    zstyle ":vcs_info:git:*" stagedstr "<S>"
    zstyle ":vcs_info:git:*" unstagedstr "<U>"
    zstyle ":vcs_info:git:*" formats "(%b) %c%u"
    zstyle ":vcs_info:git:*" actionformats "(%s)-[%b|%a] %c%u"
fi

function vcs_prompt_info() {
    LANG=en_US.UTF-8 vcs_info
    [[ -n "$vcs_info_msg_0_" ]] && echo -n " %{$fg[yellow]%}$vcs_info_msg_0_%f"
}
# end VCS

PROMPT="[%*] "
PROMPT+="%F{blue}%~%f"
PROMPT+="$(vcs_prompt_info)
"
PROMPT+="%% "

RPROMPT=""
zstyle ':vcs_info:bzr:*' use-simple true

source "/usr/local/opt/kube-ps1/share/kube-ps1.sh"
PS1='$(kube_ps1)'$PS1

ソースコードへのアクセス

ghq + pecoでCtrl + sでアクセスできるようにしている。

bindkey '^s' peco-src
function peco-src () {
    local selected_dir=$(ghq list --full-path | peco --query "$LBUFFER")
    if [ -n "$selected_dir" ]; then
        BUFFER="cd ${selected_dir}"
        zle accept-line
    fi
    zle clear-screen
}
zle -N peco-src

ブランチの切り替え

git + peco で Ctrl + b で切り替え。

bindkey '^b' peco-branch
function peco-branch() {

    # commiterdate:relativeを commiterdate:localに変更すると普通の時刻表示
    local selected_line="$(git for-each-ref --format='%(refname:short) | %(committerdate:relative) | %(committername) | %(subject)' --sort=-committerdate refs/heads refs/remotes \
        | column -t -s '|' \
        | grep -v 'origin' \
        | peco \
        | head -n 1 \
        | awk '{print $1}')"
    if [ -n "$selected_line" ]; then
        BUFFER="git checkout ${selected_line}"
        CURSOR=$#BUFFER
        zle accept-line
    fi
    zle clear-screen
}
zle -N peco-branch

github.comへのアクセス

Ctrl + o で現在開いているディレクトリのgithub.comのリポジトリへアクセスできるようにしている。


# gitのリポジトリを開く
function open-git-remote() {
  git rev-parse --git-dir >/dev/null 2>&1
  if [[ $? == 0 ]]; then
    git config --get remote.origin.url | sed -e 's#ssh://git@#https://#g' -e 's#git@#https://#g' -e 's#github.com:#github.com/#g' | xargs open
  else
    echo ".git not found.\n"
  fi
}

zle -N open-git-remote
bindkey '^o' open-git-remote

Docker

こちらもpecoで。Ctrl + t e でログイン、 Ctrl + t l でログの表示、Ctrl + t d で削除できるようにしている。Ctrl + t を押したあとに e を押すとかそんな感じ。

bindkey '^te' peco-docker-login
bindkey '^tl' peco-docker-log
bindkey '^td' peco-docker-delete
function peco-docker-login() {
    local cid=$(docker ps |grep -v 'CONTAINER ID' | peco --query "$LBUFFER"| cut -d ' ' -f1)
    if [ -n "$cid" ]; then
      BUFFER="docker exec -it $(echo $cid) /bin/bash"
      CURSOR=$#BUFFER
      zle accept-line
    fi
    zle clear-screen
}
zle -N peco-docker-login

function peco-docker-log() {
    local cid=$(docker ps |grep -v 'CONTAINER ID' | peco --query "$LBUFFER"| cut -d ' ' -f1)
    if [ -n "$cid" ]; then
      BUFFER="docker logs -f $(echo $cid)"
      CURSOR=$#BUFFER
      zle accept-line
    fi
    zle clear-screen
}
zle -N peco-docker-log
function peco-docker-delete() {
    local cid=$(docker ps |grep -v 'CONTAINER ID' | peco --query "$LBUFFER"| cut -d ' ' -f1)
    if [ -n "$cid" ]; then
      BUFFER="docker rm -f $(echo $cid)"
      CURSOR=$#BUFFER
      zle accept-line
    fi
    zle clear-screen
}
zle -N peco-docker-delete

Kubernetes

こちらもpecoまくり。Ctrl + k + c でクラスタの切り替え、Ctrl + k + n でネームスペースの切り替え、Ctrl + k + s でpodのdescribe、 Ctrl + k + d でpodの削除、 Ctrl + k + e でpodへのログイン、 Ctrl + k + l でログの表示。

bindkey '^kn'  peco-kube-namespace
bindkey '^ke'  peco-kube-exec
bindkey '^kl'  peco-kube-logs
bindkey '^kd'  peco-kube-delete-pods
bindkey '^ks'  peco-kube-describe-pods
bindkey '^kc'  peco-kube-context
function peco-kube-namespace() {
    local cid=$(kubectl get namespace |grep -v 'NAME' | peco --query "$LBUFFER"| cut -d ' ' -f1)
    if [ -n "$cid" ]; then
      BUFFER="kubectl config set-context $(kubectl config current-context) --namespace=$(echo $cid)"
      CURSOR=$#BUFFER
      zle accept-line
    fi
    zle clear-screen
}
zle -N peco-kube-namespace
function peco-kube-context() {
    local cid=$(kubectx | peco --query "$LBUFFER"| cut -d ' ' -f1)
    if [ -n "$cid" ]; then
      BUFFER="kubectx $cid"
      CURSOR=$#BUFFER
      zle accept-line
    fi
    zle clear-screen
}
zle -N peco-kube-context

function peco-kube-exec() {
    local cid=$(kubectl get pods |grep -v 'NAME' | peco --query "$LBUFFER"| cut -d ' ' -f1)
    if [ -n "$cid" ]; then
      BUFFER="kubectl exec -it $(echo $cid) /bin/bash"
      CURSOR=$#BUFFER
      zle accept-line
    fi
    zle clear-screen
}
zle -N peco-kube-exec

function peco-kube-logs() {
    local cid=$(kubectl get pods |grep -v 'NAME' | peco --query "$LBUFFER"| cut -d ' ' -f1)
    if [ -n "$cid" ]; then
      BUFFER="kubectl logs $(echo $cid)"
      CURSOR=$#BUFFER
      zle accept-line
    fi
    zle clear-screen
}
zle -N peco-kube-logs

function peco-kube-delete-pods() {
    local cid=$(kubectl get pods |grep -v 'NAME' | peco --query "$LBUFFER"| cut -d ' ' -f1)
    if [ -n "$cid" ]; then
      BUFFER="kubectl delete pods $(echo $cid)"
      CURSOR=$#BUFFER
      zle accept-line
    fi
    zle clear-screen
}
zle -N peco-kube-delete-pods

function peco-kube-describe-pods() {
    local cid=$(kubectl get pods |grep -v 'NAME' | peco --query "$LBUFFER"| cut -d ' ' -f1)
    if [ -n "$cid" ]; then
      BUFFER="kubectl describe pods $(echo $cid)"
      CURSOR=$#BUFFER
      zle accept-line
    fi
    zle clear-screen
}
zle -N peco-kube-describe-pods

ssh + tmux

僕は結構いろいろなサーバにログインすることが多く、オペミスをしないようにtmuxの機能を使って本番っぽいサーバに入ったときは背景色を変えている。色を変えてからは慎重に作業するようになった気がする。

function ssh() { # tmux起動時
    if [[ -n $(printenv TMUX) ]] ; then
        # 現在のペインIDを退避
        local pane_id=$(tmux display -p '#{pane_id}')

        hostAddr=notfound
        for arg in $@
        do
          (echo $arg | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" > /dev/null) && hostAddr=$arg
        done
        name=$(grep $hostAddr  ~/hosts | awk '{ print $2 }')
        if [[ `echo $name | grep 'staging'` ]] ; then
            tmux select-pane -t $pane_id -P 'default'
        elif [[ `echo $name | grep 'dev'` ]] ; then
            tmux select-pane -t $pane_id -P 'default'
        else
            # prod
            tmux select-pane -P 'bg=colour52,fg=white'
        fi

        # 通常通りssh続行
        command ssh $@

        # デフォルトの背景色に戻す
        tmux select-pane -t $pane_id -P 'default'
    fi
}

と、まあこんな感じでショートカットキー + pecoであれこれやっていることが多い。僕もいつか人のターミナルで動くソフトウェアを作って人の生産性を爆アゲできるようになりたい。