前言
會願意學 shell script 設計的程式設計者,通常也是老練的類 Unix 系統使用者。但我們在本文中仍會從基本開始,帶著讀者了解 shell 的基本概念。
取得類 Unix 系統
真正的 Unix 系統多用在伺服器或工作站,家用電腦上不太有機會用到。比較易於取得的則是類 Unix 系統,像是 macOS 或 GNU/Linux 等。
在類 Unix 系統中,macOS 的桌面環境做得最好,約略可取代 Windows 八成到九成的功能,而且有不少商業軟體可用。但 macOS 主機較貴,幾乎不會為了學 Unix 系統特地去買。
GNU/Linux 不是單一的作業系統,而是數種使用 Linux 核心的系統。由於 GNU/Linux 由自由軟體組成,給開發者高度自訂性,有許多團隊針對各種不同用途開發出不同的 GNU/Linux 發行版,像是適用合桌面環境的系統或是伺服器用系統。
GNU/Linux 系統本身免費,但要找到適合的硬體,才不會有硬體無法驅動的問題。可參考 Ubuntu 認證的家用電腦清單,比較不會踩到雷。台灣也有獨立商為製作音樂所打造的 GNU/Linux 筆電,可當成一般的類 Unix 系統來用。
BSD 系統則是另一大類的類 Unix 系統,比較常見的是 FreeBSD 或 TrueOS。但 BSD 系統相關的線上資料比較少,一開始不建議直接從 BSD 系統入門。
在 Windows 上,還有 Cygwin 或 WSL (Windows Subsystem for Linux) 等類 Unix 子系統可用。但這些子系統和實際的類 Unix 系統比起來仍有一些差別,有時候會碰到一些非常規的小問題,故筆者不建議只用這些子系統來學 Unix 和 shell script 。
在虛擬環境中使用類 Unix 系統
如果還不想購買實體機器,可在 VirtualBox 等虛擬機器中安裝 GNU/Linux (或其他類 Unix 系統) 來用。雖然虛擬機器的運行速度和實體機器相比差了一些,不常用類 Unix 系統的話,可以省下一些費用。
若對 Unix 還不熟悉,可以先裝在虛擬機試跑看看,覺得好用才裝在實體機器上。此外,虛擬機器可以為系統建立快照 (snapshot),所以可以把虛擬機內的系統當成測試環境,測試完再將系統回復到快照點。
近年來,雲端運算興盛,像 AWS Cloud 9 這類結合網頁 IDE 和 GNU/Linux 虛擬機器的雲端軟體成為新的選擇。這類雲端 IDE 在開完新環境後,馬上有 IDE 和 GNU/Linux 環境可用,絕對會比自己安裝系統快得多。而且這類雲端軟體用多少花多少,不用時把系統殺掉即可,所以開銷不會太大。
Shell 不只一種
Shell 是通稱,因類 Unix 系統的 shell 不只一種,系統使用者可隨自己的喜好來更換命令列環境所用的 shell。根據 shell script 的語法體系,約略可分為三種:
- Bourne shell 系列
- Sh shell (POSIX shell)
- Bash shell
- Ksh shell
- Zsh shell
- C shell 系列
- Csh shell
- Tcsh shell
- 獨立開發的 shell
- Fish shell
原本 Unix 使用的是 sh shell,相當於現在的 POSIX shell,後來 GNU 計畫寫了 Bash。Bash 除了相容於 POSIX shell 外,還加入了許多新的功能。目前 Bash 是類 Unix 系統上使用最廣的 shell。
Ksh 則是另一個增強版的 sh 相容 shell,但沒有 Bash 那麼普遍,而且 Ksh 和 Bash 互不相容。相對來說,Zsh 除了 (大部分) 相容於 Bash 外,還強化了交互性使用的體驗。
Csh 使用一套類似於 C 的語法,和 sh 不相容。Tcsh 則是 csh 的增強版。目前 Tcsh 是 FreeBSD 等系統的預設 shell,但 Tcsh 流行度不若 Bash。
除了這兩大體系外,還有一些不相容於 Bourne shell 和 C shell 的 shell,像是 Fish。由於沒有歷史包袱,Fish 等新興 shell 可以自由地加入比較新的設計。但這類新興 shell 並未成為主流。
在這麼多種 shell script 裡,要如何選擇呢?基於流行度和相容性等因素,基本上筆者只建議 POSIX shell 或 Bash。因 sh 本身是 POSIX 標準,而 Bash 則是比較流行。
許多 shell scripting 教材會直接教 Bash,但筆者建議先試著寫純 POSIX shell,只有在必要時才轉用 Bash。因 Bash 向後相容 POSIX shell,但反之則否。
我們在寫 shell script 時,把 shell 當成直譯器來用,所以平常使用的 shell 和寫 shell script 的 shell 不需要用同一個。平常使用的 shell,可以用 Zsh、Fish 等有針對互動性加強的 shell。在寫 shell 命令稿時,考量系統間的相容性,最好還是用 POSIX shell 或 Bash 來寫。
選擇寫 shell script 的編輯器
Shell 算是輕量級語言,用一般的小型編輯器來寫就可以了。甚至像 nano(1)
這種簡易的命令列編輯器都可以用來寫 shell 命令稿。所以,只要選自己用得順手的編輯器即可。
shell script 沒有函式庫
主流語言都會有函式庫 (或物件庫),可藉由呼叫函式庫 (或物件庫) 的 API 來取得特定功能。但 shell script 沒有函式庫可用,而是直接和命令列工具互動。透過各式各樣的工具來完成特定任務。
但 shell 可以用函式組織程式碼,而且可以引入其他 shell 命令稿。這些行為整體上很像是在引入外部函式庫。所以,雖然 shell script 沒有真正的函式庫,我們還是可以為命令列環境和 shell script 撰寫可重覆使用的函式。
儘量避開 AWK 或 Perl
在命令列工具中,不乏有 AWK 或 Perl 這種兼具命令列工具和程式語言的軟體。由於 AWK 或 Perl 本身具有程式語言的功能,使用起來會比其他沒有程式語言的工具來得靈活方便。但我們應謹慎地使用 AWK 或 Perl 這類大型工具,主要是效率上的考量。
AWK 或 Perl 這類工具,使用時需要解析和執行完整的程式語言,有時候還要加上讀入函式庫等動作,所以速度往往會比 grep(1)
這類小巧的工具來得慢。如果在 shell 命令稿中需要大量地呼叫 AWK 或 Perl,為什麼不乾脆直接以 AWK 或 Perl 來寫命令稿呢?
Shell 指令的種類
在 shell script 中,指令可能有以下五種來源:
- 保留字 (keywords)
- 內建指令或函式 (shell builtin)
- 別名 (alias)
- 函式 (function)
- 外部程式 (external program)
保留字是 shell 的語法,像是 if
、for
、while
等。內建指令或函式則由 shell 本身附帶,不需安裝,像 Bash 的 cd
是內建指令。這兩者都是 shell 內建的功能。
別名是由使用者自定義的字串,用來取代現有的指令,像是為指令加上一些額外的參數。函式則是一段程式碼區塊,用來封裝一至多行指令,並用有意義的名稱來命名此區塊。別名和函式都是開放給使用者自訂的功能。
至於外部程式則是系統上可取得的命令列工具。這些工具可能是執行檔 (executable) 或命令稿 (script)。兩者的差別在於程式是以編譯語言或直譯語言實作而成。
對於 shell script 來說,每執行一個外部程式,就會多開一個行程。相對來說,用內建功能不需另開行程。所以,當 shell 的效能很重要時,減少外部程式的量也是一個可能的方向。
結語
我們用了兩篇文章來介紹 shell 的特性,無非是希望讀者對 shell 能更加了解。在下一篇文章中,我們會開始寫第一個 shell script ,以熟悉 shell script 的開發流程。