位元詩人 Shell Scripting 入門

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

當前定位

Shell scripting 的核心定位始終如一:封裝流程 (workflow),也就是命令列的自動化。

若要談變化,主要在於現代有更多高階語言能撰寫指令。相比過去必須用 C 語言「裸寫」整個指令的程式碼,如今我們可以透過更高階的語言來完成同樣的工作,降低開發成本並提升可維護性。

Shell Scripting 的 Shell

「使用 shell」與「撰寫 shell script」是兩回事。
在互動式使用上,可能選擇 Bash、Zsh,甚至 Fish 等新興 shell;但在撰寫 shell script 時,建議一律使用 POSIX sh,尤其是開源專案。

Shell scripting 的本質是自動化,不應該讓 runtime 成為阻礙。
sh 是 POSIX 環境的標準,幾乎所有系統都預設安裝,使用者不必擔心環境相容性。

指令的來源

在命令稿中,指令可能有以下五種來源:

  • 保留字 (keywords)
  • 內建指令或函式 (shell builtin)
  • 別名 (alias)
  • 函式 (function)
  • 外部程式 (external program)

保留字是 shell 的語法,像是 if、for、while 等。內建指令或函式則由 shell 本身附帶,不需安裝,像 Bash 的 cd 是內建指令。這兩者都是 shell 內建的功能。

別名是由使用者自定義的字串,用來取代現有的指令,像是為指令加上一些額外的參數。函式則是一段程式碼區塊,用來封裝一至多行指令,並用有意義的名稱來命名此區塊。別名和函式都是開放給使用者自訂的功能。

至於外部程式則是系統上可取得的命令列工具。這些工具可能是執行檔 (executable) 或命令稿 (script)。兩者的差別在於程式是以編譯語言或直譯語言實作而成。

對於 shell script 來說,每執行一個外部程式,就會多開一個行程。相對來說,用內建功能不需另開行程。所以,當命令稿的效能很重要時,減少外部程式的量也是一個可能的方向。

Shell Scripting 沒有函式庫

雖然 shell scripting 本身沒有「函式庫」的概念,但可以透過 . 指令引入另一個命令稿,效果相當於載入函式庫。

為了區分用途,通常採用以下慣例:

  • 指令型命令稿:沒有副檔名,並具備可執行權限。
  • 庫型命令稿:使用 .sh 副檔名,且不設定可執行權限。

這樣能讓專案結構更清楚,避免混淆。

非必要不使用 GNU 風格參數

指令參數大致分為 GNUBSD 兩種風格。
若要追求高相容性,建議避免使用 GNU 特有的擴充功能,例如以雙連字號開頭的長參數 --long-options
在撰寫命令稿時,應優先採用各系統皆支援的基本參數,確保在不同環境下都能正常執行。

儘量避開 AWK 和 Perl

AWK 與 Perl 都是具備內嵌程式語言的命令列工具。
從 shell scripting 的角度來看,它們屬於「重型工具」,執行速度往往不如傳統指令。

雖然使用 AWK 或 Perl 撰寫命令稿相當方便,但也容易模糊邊界,讓命令稿逐漸演變成混合了 AWK 或 Perl 程式碼的腳本。
因此,除非必要,建議避免依賴這兩種工具來撰寫命令稿。

使用 Make 的時機

當多個指令之間存在相依關係,例如必須先執行 A 再執行 B,或需要偵測檔案是否更新、保存中間結果(cache)時,單純用 shell 腳本往往顯得笨重。這種情境下,改用 Make 會更合適:它能自動處理依賴、追蹤檔案變化,並避免重複執行不必要的步驟。

轉換語言的時機

Shell scripting 雖然靈活,但也容易被誤用──一些本不適合用 shell 撰寫的程式,卻被硬塞進命令稿中。

以下是常見的徵兆:

  • 在命令稿中模擬資料結構
  • 在命令稿中傳遞 JSON
  • 嘗試使用陣列或雜湊表撰寫腳本
  • 在命令稿內嵌其他語言的程式碼
  • 使用 sidecar 處理特定步驟

遇到這些情況時,直接改用高階語言撰寫指令,往往比持續硬寫 shell 命令稿更容易維護。

關於作者

位元詩人 (ByteBard) 是資訊領域碩士,專注於從探索到產品的開發過程,並以工具驅動的方式改善專案。喜歡以開源專案作為成果,回饋社群。

主要方向包括:自用工具的打磨 (dogfooding)、編譯器技術在工具開發中的應用,以及將研究轉化為可維護的開源成果。

除了技術之外,也喜歡日本料理和黑咖啡,偶爾自助旅行,將生活中的靈感融入技術隨筆。