「一個會寫 Shell Script 的工程師,等於多了一個 24 小時不休息的助手。」
— 每個深夜還在手動備份資料的工程師
什麼是 Shell Script
Shell Script 就是把一連串的 Linux 指令寫進一個 .sh 檔案,讓它自動依序執行。不需要編譯,直接由 shell(通常是 bash)解讀執行。
新增 shebang
第一行寫 #!/bin/bash,告訴系統用哪個 shell 執行
chmod +x
給腳本執行權限,否則會拒絕執行
./script.sh
用 ./ 指定當前目錄執行;或 bash script.sh
基礎語法速查
A變數
NAME = "Joseph" 是錯的,NAME="Joseph" 才是對的。B條件判斷
| 條件旗標 | 意義 | 範例 |
|---|---|---|
| -f | 檔案存在且是一般檔案 | [ -f config.txt ] |
| -d | 目錄存在 | [ -d /tmp/logs ] |
| -e | 檔案或目錄存在 | [ -e /etc/hosts ] |
| -z | 字串為空 | [ -z "$VAR" ] |
| -n | 字串非空 | [ -n "$VAR" ] |
| -eq | 數值等於 | [ $A -eq $B ] |
| -ne | 數值不等於 | [ $A -ne 0 ] |
| -gt / -lt | 大於 / 小於 | [ $N -gt 10 ] |
C迴圈
D函數定義與呼叫
特殊變數速查表
| 變數 | 意義 | 範例值 |
|---|---|---|
| $0 | 腳本本身的名稱 | ./deploy.sh |
| $1 ... $9 | 第 1 ~ 9 個傳入參數 | $1 = "production" |
| $# | 傳入參數的數量 | 3(傳了三個參數) |
| $@ | 所有參數(陣列形式) | "arg1" "arg2" "arg3" |
| $? | 上一個指令的結束碼(exit code) | 0 = 成功,非 0 = 失敗 |
| $$ | 目前 shell 的 PID | 12345 |
| $! | 最後一個背景執行的 PID | 12346 |
| $HOME | 目前使用者的家目錄 | /home/joseph |
| $PATH | 可執行檔搜尋路徑 | /usr/bin:/usr/local/bin... |
10 個實用腳本模板
這 10 個模板都是實際工作中常用的,直接複製後改參數就能用。
備份資料夾 → 帶時間戳的 zip
批次重命名檔案(加前綴)
監控磁碟空間,超過閾值寫入 alert log
等待服務啟動後再執行下一步
讀取 CSV 逐行處理
自動 git commit + push
環境變數檢查腳本(部署前確認)
批次 SSH 遠端執行指令
解壓縮並移動到指定目錄
每隔 N 秒輪詢,直到條件成立
常見錯誤與 Debug 技巧
Shell Script 最難的不是邏輯,而是各種隱藏的「空白問題」和靜默失敗。這幾個技巧可以幫你快速定位問題:
最常見的變數空白 Bug
變數值含有空格時,不加引號會被 shell 拆成多個參數。 例如
FILE="my file.txt", rm $FILE 等於 rm my file.txt(兩個參數), 但 rm "$FILE" 才是正確的(一個參數)。set -e
遇到錯誤立即停止。防止在某步驟失敗後繼續執行,造成更大災難
set -x
Debug 模式。逐行印出即將執行的指令,方便看腳本執行到哪一步出問題
set -u
未定義變數報錯。避免打錯變數名卻默默當空字串使用
面試常考題
Q1. $? 是什麼?0 代表什麼?
$? 是上一個指令的 exit code(結束碼)。0 代表成功,任何非 0 的值代表失敗(具體數值由程式自定義,通常 1 是一般錯誤,2 是用法錯誤)。這是腳本中做錯誤判斷的最基本機制。
Q2. 如何接收腳本參數?
用 $1, $2... 取得位置參數,$# 取得參數個數,$@ 取得全部參數(陣列形式)。在腳本開頭做參數個數檢查是好習慣。
Q3. 2>/dev/null 是什麼意思?
Linux 有三個標準 I/O 串流:0=stdin, 1=stdout, 2=stderr。2>/dev/null 把 stderr(錯誤輸出)導向 /dev/null(黑洞,丟棄所有輸入)。常用於「不想看到錯誤訊息,只關心是否成功」的場景。
Q4. heredoc 中 EOF 的用法?
Heredoc(Here Document)讓你在 shell script 中直接嵌入多行文字,不需要轉義引號。EOF 是慣用的結束標記(可以用任何字串),結束標記必須獨立一行且頂格。
Shell Script 的核心原則
- →永遠在腳本頂端加 set -euo pipefail,讓錯誤無所遁形
- →變數一律加雙引號,避免空格造成的隱性 bug
- →腳本開頭做參數個數驗證,提前失敗好過靜默錯誤
- →用 $? 或 && / || 做流程控制,而非假設每個指令都成功
- →Debug 時用 set -x,上線前記得移除或關掉