Z Shell(Zsh)是macOS預設的Shell,它能夠提供比Bash還要更強大的TAB補全功能,也可以做到補全時大小寫字母的更正。如果再加上Oh My Zsh框架,還能快速設定Zsh的主題(theme)以及各式擴充插件(plugin)。Zsh的語法與Bash是大同小異,將Linux預設的Shell改為Zsh後也可以在需要時隨時使用Bash來跑Bash腳本,不太會有轉換前後有所差異的困擾。



檢查目前預設的Shell

在終端機執行以下指令,可以查看目前使用者預設的Shell程式的路徑。

echo $SHELL

zsh

如上圖,可以知道目前使用者的預設Shell為Bash。

安裝 Zsh

基於Debian的Linux發行版可以使用以下指令來安裝Zsh:

sudo apt install zsh

紅帽系的Linux發行版可以使用以下指令來安裝Zsh:

sudo dnf install zsh

進入 Zsh

安裝完Zsh後,在終端機執行zsh指令即可進入Zsh。

第一次執行Zsh,由於使用者的家目錄中沒有.zshrc檔案,因此會出下如下圖的設定畫面。

zsh

由於等等會介紹使用Oh My Zsh來產生.zshrc檔案,因此這邊可以先按下0來略過.zshrc檔案的產生。

進入Zsh後,應該會看到如下圖的畫面。

zsh

如上圖,可以看到此時的提示字元(prompt)變得很樸素,不太好看。別擔心,本篇文章稍候會說明要怎麼修改Zsh的主題。

如果是要進入SSH伺服器的Zsh的話,可以使用如下的指令來登入SSH伺服器:

ssh -t user@host "zsh -l"

ssh-t參數可以在進行SSH登入後同時去執行某個指令時強制使用偽終端(pseudo-terminal)。由於我們要在SSH伺服器上執行的指令是zsh -l,它會需要一個偽終端,所以才要在ssh指令加上這個-t參數。

zsh加上-l參數,是為了要讓它成為所謂的Login Shell(登入型Shell)。Login Shell就是使用者在進行登入行為之後會使用的Shell模式,有無Login Shell的差異是,有一些Shell的初始化腳本是只有在一開始進入Login Shell的時候才會去跑的。而且除了Login Shell之外,還有所謂的Interactive Shell(互動式Shell),能夠出現提示字元讓使用者輸入指令的Shell就是Interactive Shell。一個Shell是可以同時擁有Login和Interactive這兩種屬性。

以下是Zsh會自動執行的腳本路徑、執行順序(從上到下)和執行時機的表格:

Zsh腳本路徑 執行時機 對應的Bash腳本路徑
/etc/zsh/zshenv 每次進入Shell時。 ${BASH_ENV}
~/.zshenv 每次進入Shell時。 同上。
/etc/zsh/zprofile 每次進入Login Shell時。 /etc/profile
其中又會去呼叫/etc/profile.d/*.sh
~/.zprofile 每次進入Login Shell時。 從這三個檔案按照順序挑一個出來執行:
1. ~/.bash_profile
2. ~/.bash_login
3. ~/.profile
/etc/zsh/zshrc 每次進入Interactive Shell時。 /etc/bash.bashrc
~/.zshrc 每次進入Interactive Shell時。 ~/.bashrc
/etc/zsh/zlogin 每次進入Login Shell時。
~/.zlogin 每次進入Login Shell時。

修改目前使用者的預設Shell為Zsh

每次都要執行zsh指令才能從Sh或是Bash進入Zsh,實在太麻煩了。我們可以執行以下指令,將目前使用者的預設Shell設為Zsh:

chsh -s /bin/zsh

zsh

如此一來,下次登入這個使用者,預設就會使用Zsh了!

如果要修改別的使用者的預設Shell為Zsh,可以執行如下的指令:

sudo chsh -s /bin/zsh <使用者名稱>

Oh My Zsh

安裝 Oh My Zsh

Oh My Zsh是非常多人使用的Zsh組態設定的管理框架。使用Oh My Zsh前,要先在Linux環境中安裝Git和cURL。

基於Debian的Linux發行版可以使用以下指令來安裝Git和cURL:

sudo apt install git curl

紅帽系的Linux發行版可以使用以下指令來安裝Git和cURL:

sudo dnf install git curl

執行以下指令來下載並安裝Oh My Zsh:

curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | sh -s

zsh

如上圖,看到那個五彩繽紛的畫面,就表示Oh My Zsh安裝成功了!

可以打開~/.zshrc檔案看一下Oh My Zsh把它變成什麼樣子了。

zsh

設定主題

Oh My Zsh預設的主題也是十分簡潔。如果要更換的話,可以到Oh My Zsh的GitHub頁面上找到主題列表和截圖,網址如下:

例如筆者想要將主題換成risto,就去修改~/.zshrc檔案中ZSH_THEME變數的值:

ZSH_THEME="risto"

zsh

接著執行source ~/.zshrc指令,就可以套用新的主題。如下圖:

zsh

客製化主題

risto主題雖然已經比較接近Linux Mint Cinnamon的風格了,但還是有明顯差異,如下圖。

zsh

筆者想要讓Zsh的主題與Bash的相同,所以執行了以下指令,將risto主題複製了一份到Oh My Zsh所設定的${ZSH_CUSTOM}目錄下,這個目錄的設定檔會比${ZSH}下的還要晚讀取,可以覆寫過去。

cp $ZSH/themes/risto.zsh-theme $ZSH_CUSTOM/themes/risto.zsh-theme

zsh

所以接下來就是要編輯剛才複製出來的檔案了。

zsh

zsh

要讓risto主題長得跟Linux Mint Cinnamon的風格一樣,只要把登入的使用者和主機名稱的部份變成粗體,並消除錢字號$前的空格就好了。所以可以將PROMPT變數做如下的修改:

PROMPT='%{$fg[green]%}%B%n@%m%b:%{$fg_bold[blue]%}%2~$(git_prompt_info)%{$reset_color%}%(!.#.$) '

%B是粗體的起始;%b是粗體的終止。

如果想要改顏色的話,可以去修改$fg函數的參數。可以使用以下的8色英文單字:black、red、green、yellow、blue、magenta、cyan、white。

或者也可以使用如下圖表的256色編號:

vimrc

在Zsh也可以執行spectrum_ls或是spectrum_bls來查看這些色票。

zsh

zsh

不過要使用256色編號,或是指定的RGB色碼的話,要將$fg[...]改成%F{...}。例如要將綠色的$fg[green]改成編號為80的藍綠色,就要寫成%F{80},或是%F{#5fd7d7}(十六進制色碼的英文字母大小寫都可)。

修改完後,執行source ~/.zshrc指令,提示字元的風格就是我們想要的了!

zsh

risto主題的PROMPT有一點值得注意的地方是,它用了%2~來抓取當前工作目錄的路徑的最後兩層。如果想要顯示完整的路徑,可以將其修改為%~

設定擴充插件

~/.zshrc檔案中的plugins變數的值,就是在設定要啟用哪些擴充插件,以空格或是換行隔開多個擴充套件。

zsh

預設已經啟用git,若Zsh的工作目錄在Git專案下,就會顯示當前是在哪個分支。

zsh

Oh My Zsh的GitHub頁面上可以找到擴充插件列表和說明,網址如下:

停用自動檢查更新

Oh My Zsh預設會自動檢查更新,這會導致每次進入Shell的時候都需要等待一段時間讓它檢查更新,建議將自動檢查更新功能停用,改用手動的方式進行更新。

執行以下指令可停用自動檢查更新:

zstyle ':omz:update' mode disabled

執行以下指令可啟用自動檢查更新:

zstyle ':omz:update' mode auto

執行以下指令可手動更新:

omz update

指令歷史

Oh My Zsh會幫忙提高Zsh所記錄的指令數量,不太會需要去修改。如果您覺得不夠用,可以在~/.zshrc檔案中設定HISTSIZESAVEHIST變數的值。HISTSIZE變數用來設定一個Shell最多要儲存多少筆指令;SAVEHIST變數用來設定儲存指令的檔案最多要儲存多少筆指令。其實就是對應Bash的HISTSIZEHISTFILESIZE變數啦。

若要查看或是刪除Zsh的指令歷史,也是直接在Zsh使用history指令即可。

預設文字編輯器

按照這篇文章來設定即可:

只不過要記得把export EDITOR=vim加在~/.zshrc檔案中。

快速鍵風格

Zsh預設的快速鍵風格是Emacs,如果想要改成Vi,可以參考這篇文章:

在Zsh下,其實也可以用bindkey -v指令來取代set -o vi指令。

一旦Zsh的快速鍵風格被設為Vi,Ctrl + r搜尋指令歷史的用法就會被取消掉,可以再執行以下指令將其加回(十分建議):

bindkey '^R' history-incremental-search-backward