インストール - Zsh

提供:MochiuWiki : SUSE, EC, PCB
2021年9月23日 (木) 09:58時点におけるWiki (トーク | 投稿記録)による版 (→‎Zshの設定例)
ナビゲーションに移動 検索に移動

概要

Zshはシェルの一種で、Linux等の標準シェルであるbashよりも便利な機能を持ったシェルである。

Linuxにてターミナルでコマンドを実行することが多々あるが、zshに切り替えることで、作業効率を上げることができる。

ここでは、Zshの最新版をインストールする方法を記載する。
なお、CentOSのパッケージ管理システムでは、最新のZshをインストール出来ないため、yumは使用しない。

最新のZshはこちらのWebサイトで確認できる。


Zshのインストール

CentOS / SUSE

まず、CentOSでは、Zshのインストールするにはncurses-develが必要となるので、以下のコマンドを実行してインストールする。

# CentOS
sudo yum install ncurses-devel

# SUSE
sudo zypper install ncurses-devel


次に、以下に示すZshの公式WebサイトまたはSouceforgeから、Zshのソースコードをダウンロードする。


Zshのビルドでは、ビルドディレクトリを作成しないこと。

wget https://sourceforge.net/projects/zsh/files/zsh/<バージョン名>/zsh-<バージョン名>.tar.xz/download -O zsh-<バージョン名>.tar.xz
tar xf zsh-<バージョン名>.tar.xz -C zsh-src
cd zsh-src


次に、Zshをビルドおよびインストールする。
ここで、--enable-multibyteオプションは、マルチバイトを有効にするオプションである。

./configure --enable-multibyte --prefix=$HOME/InstallSoftware/zsh
make -j $(nproc)
make install


※注意
configureスクリプトの実行において、以下に示すエラーが出力される時がある。

config.status: error: cannot find input file: `config.h.in'


この時、autoheaderコマンドを実行して、config.h.inファイルを作成する。

autoheader


Raspberry Pi

CentOSと同様、Zshのインストールするにはncurses-develが必要となるので、以下のコマンドを実行してインストールする。

sudo apt install libncurses5-dev libncursesw5-dev libtinfo-dev


ビルドおよびインストールは、CentOS / SUSEと同様である。


Zshの使用

Zshを利用可能なシェル一覧に追加する。
ここに追加することで、chshコマンドでシェルの変更が可能となる。

sudo echo /<zshのインストールディレクトリ>/bin/zsh >> sudo /etc/shells


次に、ユーザのシェルを変更する。(コマンドを実行するとパスワードの入力が必要となる)

chsh -s /<zshのインストールディレクトリ>/bin/zsh


再度ログインするか再起動を行う。

すると、以下の文言が表示される。これは、Zshに設定ファイルが存在しないために表示される。
ここでは、 0を入力して空の設定ファイルを作成する。

This is the Z Shell configuration function for new users, zsh-newuser-install.
You are seeing this message because you have no zsh startup files(the files .zshenv, .zprofile, .zshrc, .zlogin in the directory~).
This function can help you with a few settings that should make your use of the shell easier.

You can:

(q)  Quit and do nothing.  The function will be run again next time.

(0)  Exit, creating the file ~/.zshrc containing just a comment.
    That will prevent this function being run again.

(1)  Continue to the main menu.

--- Type one of the keys in parentheses ---



エラー

Zshを起動した時、以下のようなエラーが発生する場合がある。

stty: invalid integer argument〜


Zshでは、^(キャレット)は拡張グロブ文字であり、コマンド処理のファイル名拡張部分で認識される。

例えば、^Mは、Mにマッチするものを除く全てのファイル名にマッチする。
この時、stty eraseに続き、カレントディレクトリにMという名前のファイルがあれば、それを除く全てのファイル名を展開するということである。

このエラーを回避するには、^(キャレット)文字を使用している箇所を、引用またはエスケープする必要がある。

'^M'
または
\^M


または、~/.zshrcファイルにおいて、Zshの拡張グロブを無効にする。

 setopt NO_EXTENDED_GLOB



Zshの設定例

Zshの設定ファイルを作成した後、以下に示すような設定を記述する。

vi ~/.zshrc


 # ~/.zshrcファイル
 
 # Ctrl + Dでログアウトしてしまうことを防ぐ
 setopt IGNOREEOF
 
 # 既存のファイルをリダイレクトで上書きしない
 setopt NOCLOBBER
 
 # 日本語を使用
 # export LANG=ja_JP.UTF-8
 
 # パスを追加したい場合
 # export PATH="$HOME/bin:$PATH"
 
 # 色を使用
 autoload -Uz colors
 colors
 
 # 自動補完を有効にする
 # コマンドの引数やパス名を途中まで入力して <Tab> を押すといい感じに補完してくれる
 # 例: `cd path/to/<Tab>`, `ls -<Tab>`
 autoload -Uz compinit
 compinit
 
 # Emacsに似た操作を有効にする(文字入力中に Alt-Right, Alt-Leftでカーソル移動等)
 # Viに似た操作が好みであれば bindkey -v とする
 bindkey -e
 #bindkey "\E[1;3C" emacs-forward-word   # Alt-Right, Alt-Leftでカーソル移動
 #bindkey "\E[1;3D" emacs-backward-word  # Alt-Right, Alt-Leftでカーソル移動
 bindkey ";5C" emacs-forward-word      # Ctrl-Right, Ctrl-Leftでカーソル移動
 bindkey ";5D" emacs-backward-word     # Ctrl-Right, Ctrl-Leftでカーソル移動
 
 # 他のターミナルとヒストリーを共有
 setopt share_history
 
 # ヒストリーに重複を表示しない
 setopt HIST_IGNORE_ALL_DUPS
 
 # 重複している行は無視する
 setopt HIST_IGNORE_DUPS
 
 # 履歴ファイルから空の行を削除する
 setopt HIST_REDUCE_BLANKS
 
 # 空白から始めたコマンドを無視
 setopt HIST_IGNORE_SPACE
 
 # historyコマンドとfcコマンドを履歴に追加しない
 setopt HIST_NO_STORE
 
 HISTFILE=~/.zsh_history
 HISTSIZE=100
 SAVEHIST=100
 
 # 入力したコマンドが存在せず、かつディレクトリ名と一致するなら、ディレクトリに cd する
 # 例: /usr/bin と入力すると /usr/bin ディレクトリに移動
 setopt auto_cd
 
 # cd した先のディレクトリをディレクトリスタックに追加する
 # ディレクトリスタックとは今までに行ったディレクトリの履歴のこと
 # `cd +<Tab>` でディレクトリの履歴が表示され、そこに移動できる
 setopt auto_pushd
 
 # pushdから重複を削除
 setopt pushd_ignore_dups
 
 # コマンドミスを修正
 setopt correct
 
 # グローバルエイリアス
 alias -g cd=' cd -P'
 alias -g rm='rm -iv'
 alias -g cp='cp -i'
 alias -g mv='mv -iv'
 alias -g ls=' ls -hlvF --group-directories-first --color'
 alias -g cat=' cat -n'
 alias -g less=' less -n'
 alias -g grep=' grep -i'
 alias -g en=' LANG=C LANGUAGE=C LC_ALL=C'
 alias -g jp='LANG=ja_JP.UTF-8'
 alias -g mount='mount -o ro,noload'
 alias -g umount='umount -fl'
 alias -g nano='nano -lmS'
 alias -g L='| less'
 alias -g H='| head'
 alias -g G='| grep'
 alias -g GI='| grep -ri'
 alias -g D='--detail'
 alias -g PROG='& progress -mp $!'  # Progress(進捗表示ツール)をインストールしている場合
 
 # エイリアス
 alias which=' which'
 alias clear=' clear && echo -en "\e[3J"'
 alias hclear=' rm -rf ~/.zsh_history 1>/dev/null && touch ~/.zsh_history 1>/dev/null'
 alias igrep=' sudo zypper search -i'
 alias repoclean=' sudo zypper clean -a'
 alias skate='kdesu /usr/bin/kate'
 alias scode='code --user-data-dir=$HOME/Program/VScode_root_project'
 alias suse=' cat /etc/SUSE-brand'
 alias upoweroff=' sudo systemctl poweroff'
 alias ureboot=' sudo systemctl reboot'
 alias startx=' startx'
 alias exit=' exit'
 alias gexit=' echo <パスワード> | sudo -S systemctl stop graphical.target; echo <パスワード> | sudo -S systemctl restart multi-user.target'
 alias kde=' echo <パスワード> | sudo -S systemctl restart graphical.target'
 alias gnome=' echo <パスワード> | sudo -S systemctl restart graphical.target'
 alias uoff=' sudo systemctl poweroff'
 alias ureboot=' sudo systemctl reboot'
 alias fw=' sudo firewall-cmd'
 alias fwr='sudo firewall-cmd --reload'
 alias fwp='sudo firewall-cmd --permanent'
 alias fwrp='sudo firewall-cmd --runtime-to-permanent'
 alias startnm=' sudo systemctl stop wickedd wicked; sudo systemctl start NetworkManager'
 alias startwicked=' sudo systemctl stop NetworkManager; sudo systemctl start wickedd wicked'
 
 alias plasma=' /usr/bin/kquitapp5 plasmashell; plasmashell > /dev/null 2>&1 & disown; sleep 2; exit'
 #alias plasma=' killall plasmashell; plasmashell > /dev/null 2>&1 & disown'
 
 alias sshpi='ssh <ユーザ名>@<ホスト名またはIPアドレス> -p <ポート番号> -i <暗号鍵ファイルのフルパス>'
 alias sshsakura=' sshpass -p <パスワード> ssh <ユーザ名>@<ホスト名またはIPアドレス> -p <ポート番号>'
 
 # FreeRDPをインストールしている場合
 alias rwin10=' $HOME/InstallSoftware/FreeRDP/freerdp-nightly/bin/xfreerdp /u:<仮想マシンのユーザ名> /p:<パスワード> /w:1600 /h:900 +clipboard /sound:rate:44100,channel:2 /drive:<共有ディレクトリ名>,<共有ディレクトリのフルパス> /v:<仮想マシンのIPアドレス>'
 
 # WebStormをインストールしている場合
 # alias resetWS=' find ~/.config/JetBrains/WebStorm2020.3/eval -type f -mtime +25 -delete'
 alias resetWS=' sh -c $HOME/InstallSoftware/WebStorm/WebStorm_2020_3/Trial_Restart.sh'
  
 # backspace,deleteキーを使えるように
 stty erase ^H
 bindkey "^[[3~" delete-char
 
 # cdの後にlsを実行
 chpwd()
 {
    ls -hlFtr --color=auto
 }
 
 # どこからでも参照できるディレクトリパス
 #cdpath=(~)
 
 # 区切り文字の設定
 autoload -Uz select-word-style
 select-word-style default
 zstyle ':zle:*' word-chars "_-./;@"
 zstyle ':zle:*' word-style unspecified
 
 # Ctrl + sのロック, Ctrl + qのロック解除を無効にする
 setopt no_flow_control
 
 # プロンプトを2行で表示、時刻を表示
 #PROMPT="%(?.%{${fg[green]}%}.%{${fg[red]}%})%n${reset_color}@${fg[blue]}%m${reset_color}(%*%) %~%# "
 # または
 PROMPT="%(?.%{${fg[red]}%}.%{${fg[red]}%})%n${reset_color}@${fg[green]}%m${reset_color}(%*%) Using Zsh
 > "
 
 # <Tab> でパス名の補完候補を表示した後、続けて<Tab>を押すと候補からパス名を選択できるようになる
 # 補完後、メニュー選択モードになり左右キーで移動が出来る
 zstyle ':completion:*:default' menu select=2
 
 # 補完で大文字にもマッチ
 zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
 
 # Ctrl+rでヒストリーのインクリメンタルサーチ、Ctrl+sで逆順
 bindkey '^r' history-incremental-pattern-search-backward
 bindkey '^s' history-incremental-pattern-search-forward
 
 # コマンドを途中まで入力後、historyから絞り込み
 # 例 ls まで打ってCtrl+pでlsコマンドをさかのぼる、Ctrl+bで逆順
 autoload -Uz history-search-end
 zle -N history-beginning-search-backward-end history-search-end
 zle -N history-beginning-search-forward-end history-search-end
 bindkey "^p" history-beginning-search-backward-end
 bindkey "^b" history-beginning-search-forward-end
 
 # cdrコマンドを有効 ログアウトしても有効なディレクトリ履歴
 # cdr タブでリストを表示
 autoload -Uz add-zsh-hook
 autoload -Uz chpwd_recent_dirs cdr
 add-zsh-hook chpwd chpwd_recent_dirs
 
 # cdrコマンドで履歴にないディレクトリにも移動可能に
 zstyle ":chpwd:*" recent-dirs-default true
 
 # 複数ファイルのmv 例 zmv *.txt *.txt.bk
 autoload -Uz zmv
 alias zmv='noglob zmv -W'
 
 # 改行のない出力をプロンプトで上書きするのを防ぐ
 unsetopt promptcr
 
 # mkdirとcdを同時実行
 function mkcd()
 {
    if [ "${#}" -ne 1 ]; then
       echo "Specify Arguments." 1>&2
       return 1
    fi
 
    if [ -d $1 ]; then
       echo "$1 already exists!" 
       cd $1
    else
       mkdir -p $1 && cd $1
    fi
 
    return 0
 }
 
 # manコマンドの結果を標準のWebブラウザで閲覧
 function manh()
 {
    if [ "$#" -eq 0 ]; then
       echo "Too few arguments!"
    elif [ "$#" -eq "1" ]; then
       man --html=firefox $1 &
    else
       echo "Too many arguments!"
    fi
 }
 
 # Change Private IP Address
 function chip()
 {
    if [ ${#} != 1 ]; then
       echo "The argument is wrong." >&2
       return 1
    fi
 
    sudo nmcli device disconnect eth0
    sudo systemctl stop NetworkManager
 
    sudo sed -i -e "s/^address1=.*/address1="${1}"\/24,192.168.1.1/g" /etc/NetworkManager/system-connections/Wired.nmconnection
 
    sudo systemctl start NetworkManager
    sudo nmcli device connect eth0
 
    return 0
 }
 
 # KVMの起動
 function startkvm
 {
    KVM_STATUS=$(sudo systemctl status libvirtd | grep "Active:" | grep -ie "dead")
    if [ -n "KVM_STATUS" ]; then
       sudo systemctl start libvirtd
    fi
 
    NETWORK_STATUS=$(sudo virsh net-info default | grep -ie "起動中" -ie "Active" | grep -ie "no")
    if [ -n "$NETWORK_STATUS" ]; then
       sudo virsh net-start default
    fi
 
    local FIREWALL_STATUS=$(sudo systemctl status firewalld | grep "Active:" | grep -ie "running")
    if [ -n "FIREWALL_STATUS" ]; then
       sudo systemctl stop firewalld
    fi
 }
 
 # KVMの停止
 function stopkvm
 {
    NETWORK_STATUS=$(sudo virsh net-info default | grep -ie "起動中" -ie "Active" | grep -ie "yes")
    if [ -n "$NETWORK_STATUS" ]; then
       sudo virsh net-destroy default
    fi
 
    KVM_STATUS=$(sudo systemctl status libvirtd | grep "Active:" | grep -ie "running")
    if [ -n "KVM_STATUS" ]; then
       sudo systemctl stop libvirtd libvirtd.socket libvirtd-admin.socket libvirtd-ro.socket
    fi
 
    local FIREWALL_STATUS=$(sudo systemctl status firewalld | grep "Active:" | grep -ie "dead")
    if [ -n "FIREWALL_STATUS" ]; then
       sudo systemctl restart firewalld
    fi
 }
 
 # カレントディレクトリに存在するディレクトリとファイルの検索
 function lgrep()
 {
    if [ "$#" -eq 1 ]; then
       local IFS_BACKUP=$IFS
       IFS=$'\n\t'
 
       for OBJECT in $(\ls -aA --group-directories-first | \grep -iE "${1}")
       do
          \ls -AdhlF --color "${OBJECT}"
       done
 
       echo ""
 
       IFS=$IFS_BACKUP
    elif [ "$#" -eq 2 ]; then
       # 第1引数で指定したディレクトリが存在するか確認する
       if [ ! -d "$1" ]; then
          echo "Not Exist Directory $1" 1>&2
          return 1
       fi
 
       local IFS_BACKUP=$IFS
       IFS=$'\n\t'
 
       # 上記で定義しているchpwd関数を無効化する
       disable -f chpwd
 
       # 現在のカレントディレクトリを一時的に保存する
       local CURRENTDIR=$(\pwd)
 
       # 第1引数で指定したディレクトリに移動する
       cd "${1}";
 
       # 第2引数で指定したパターンを使用して検索する
       for OBJECT in $(\ls -aA --group-directories-first | \grep -iE "${2}")
       do
          \ls -AdhlF --color "${OBJECT}"
       done
 
       # カレントディレクトリに戻る
       cd "${CURRENTDIR}"
 
       echo ""
 
       IFS=$IFS_BACKUP
 
       # 上記で定義しているchpwd関数を有効化する
       enable -f chpwd
 
       unset -v OBJECT
    else
       echo "Specify Arguments." 1>&2
    fi
 
    return 0
 }
 
 # カレントディレクトリから特定のファイルを検索後、パターンにマッチするファイル内容を抽出する
 function datagrep()
 {
    if [ "$#" -eq 1 ]; then
       if [ "${1}" = '-h' -o "${1}" = '--h' -o "${1}" = '-help' -o "${1}" = "--help" ]; then
          echo "Usage:"
          echo "   Ex.1: filegrep <File Patern> <File Data Pattern>"
          echo "   Ex.2: filegrep <Search Directory> <File Patern> <File Data Pattern>"
 
          return 0
       fi
    fi
 
    if [ "$#" -eq 2 ]; then
       local IFS_BACKUP=$IFS
       IFS=$''
 
       for OBJECT in $(\find . -type f -iname "${1}" -print0 | \xargs -0 \grep -inE "${2}")
       do
          echo "${OBJECT}"
       done
 
       echo ""
 
       IFS=$IFS_BACKUP
    elif [ "$#" -eq 3 ]; then
       # 第1引数で指定したディレクトリが存在するか確認する
       if [ ! -d "$1" ]; then
          echo "Not Exist Directory $1" 1>&2
          return 1
       fi
 
       local IFS_BACKUP=$IFS
       IFS=$''
 
       # 上記で定義しているchpwd関数を無効化する
       disable -f chpwd
 
       # 現在のカレントディレクトリを一時的に保存する
       local CURRENTDIR=$(\pwd)
 
       # 第1引数で指定したディレクトリに移動する
       cd "${1}";
 
       # 第2引数で指定したパターンを使用して検索する
       for OBJECT in $(\find . -type f -iname "${2}" -print0 | \xargs -0 \grep -inE "${3}")
       do
          echo "${OBJECT}"
       done
 
       # カレントディレクトリに戻る
       cd "${CURRENTDIR}"
 
       echo ""
 
       IFS=$IFS_BACKUP
 
       # 上記で定義しているchpwd関数を有効化する
       enable -f chpwd
 
       unset -v OBJECT
    else
       echo "Specify Arguments." 1>&2
    fi
 
    return 0
 }
 
 function fwl()
 {
    # converts output to zsh array ()
    # @f flag split on new line
    zones=("${(@f)$(sudo firewall-cmd --get-active-zones | grep -v 'interfaces\|sources')}")
 
    for i in $zones; do
       sudo firewall-cmd --zone $i --list-all
    done
 
    echo 'Direct Rules:'
    sudo firewall-cmd --direct --get-all-rules
 }
 
 # Apache2とMySQLの起動
 function startlamp()
 {
    local APACHE2_STATUS=$(sudo systemctl status apache2 | grep -ie "Active:" | grep -ie "dead")
    if [ -n "APACHE2_STATUS" ]; then
       sudo systemctl start apache2
    fi
 
    local MYSQL8_STATUS=$(sudo systemctl status mysql | grep -ie "Active:" | grep -ie "dead")
    if [ -n "MYSQL8_STATUS" ]; then
       sudo systemctl start mysql
    fi
 }
 
 # Apache2とMySQLの停止
 function stoplamp()
 {
    local APACHE2_STATUS=$(sudo systemctl status apache2 | grep "Active:" | grep -ie "running")
    if [ -n "APACHE2_STATUS" ]; then
       sudo systemctl stop apache2
    fi
 
    local MYSQL8_STATUS=$(sudo systemctl status mysql | grep "Active:" | grep -ie "running")
    if [ -n "MYSQL8_STATUS" ]; then
       sudo systemctl stop mysql
    fi
 }
 
 # 環境変数PATHの設定
 function SetPATH()
 {
    BEFORE_HOME='$HOME'
    AFTER_HOME="$HOME"
    PATH_NAME=$(echo ${1//"$BEFORE_HOME"/"$AFTER_HOME"})
    
    SLASH=$(echo ${PATH_NAME: -1:1})
    if [ $SLASH = "/" ]; then
       LENGTH="${#PATH_NAME}"
       let LENGTH=$LENGTH-1
       PATH_NAME=$(echo ${PATH_NAME:0:$LENGTH})
    fi
    
    if [ ! -d $PATH_NAME ]; then
       echo "No Exist Directory $PATH_NAME"
       return 1
    fi
    
    EXIST_FLAG=0
    for VALUE in ${(s/:/)PATH}
    do
       if [ "$VALUE" = "$PATH_NAME" ]; then
          EXIST_FLAG=1
          break
       fi
    done
    
    if [ "$EXIST_FLAG" -eq 0 ]; then
       export PATH="$PATH_NAME:$PATH"
    elif [ $EXIST_FLAG -eq 1 ]; then
       echo "Already Exist $PATH_NAME in PATH " 1>&2
    fi
    
    unset -v SLASH LENGTH BEFORE_HOME AFTER_HOME PATH_NAME EXIST_FLAG VALUE
    
    return 0
 }
 
 function SetLIBRARY()
 {
    BEFORE_HOME='$HOME'
    AFTER_HOME="$HOME"
    PATH_NAME=$(echo ${1//"$BEFORE_HOME"/"$AFTER_HOME"})
    
    SLASH=$(echo ${PATH_NAME: -1:1})
    if [ $SLASH = "/" ]; then
        LENGTH="${#PATH_NAME}"
        let LENGTH=$LENGTH-1
        PATH_NAME=$(echo ${PATH_NAME:0:$LENGTH})
    fi
    
    if [ ! -d $PATH_NAME ]; then
        echo "No Exist Directory $PATH_NAME"
        return 1
    fi
    
    EXIST_FLAG=0
    for VALUE in ${(s/:/)LD_LIBRARY_PATH}
    do
        if [ "$VALUE" = "$PATH_NAME" ]; then
            EXIST_FLAG=1
            break
        fi
    done
    
    if [ $EXIST_FLAG -eq 0 ]; then
        export LD_LIBRARY_PATH="$PATH_NAME:$LD_LIBRARY_PATH"
    elif [ $EXIST_FLAG -eq 1 ]; then
        echo "Already Exist $PATH_NAME in LD_LIBRARY_PATH " 1>&2
    fi
    
    unset -v SLASH LENGTH BEFORE_HOME AFTER_HOME PATH_NAME EXIST_FLAG VALUE
    
    return 0
 }
  
 # git設定
 RPROMPT="%{${fg[blue]}%}[%~]%{${reset_color}%}"
 autoload -Uz vcs_info
 setopt prompt_subst
 zstyle ':vcs_info:git:*' check-for-changes true
 zstyle ':vcs_info:git:*' stagedstr "%F{yellow}!"
 zstyle ':vcs_info:git:*' unstagedstr "%F{red}+"
 zstyle ':vcs_info:*' formats "%F{green}%c%u[%b]%f"
 zstyle ':vcs_info:*' actionformats '[%b|%a]'
 precmd () { vcs_info }
 RPROMPT=$RPROMPT'${vcs_info_msg_0_}'