インストール - 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_}'