test(或 [ ])是 Shell 腳本條件判斷的基石。本文系統整理檔案測試、字串比較、整數比較、邏輯運算與實戰模式,並釐清 test、[ ]、[[ ]]、(( )) 的差異。
基本語法與回傳值
test 條件表達式
# 等價
[ 條件表達式 ] # POSIX 標準,需空格分隔
# 回傳值
$? # 0 = true(成功),非 0 = false(失敗/錯誤碼)
檔案測試運算子(最常用)
| 運算子 | 條件為真當... | 範例 |
| -e FILE | 檔案存在 | test -e /etc/passwd |
| -f FILE | 一般檔案 | test -f /etc/passwd |
| -d FILE | 目錄 | test -d /home/user |
| -r FILE | 可讀 | test -r file.txt |
| -w FILE | 可寫 | test -w file.txt |
| -x FILE | 可執行 | test -x script.sh |
| -s FILE | 大小 > 0 | test -s log.txt |
| -L FILE | 符號連結 | test -L /usr/bin/python |
| -S FILE | Socket | test -S /var/run/docker.sock |
| -p FILE | 命名管道 | test -p /tmp/fifo |
| -b FILE | 區塊裝置 | test -b /dev/sda |
| -c FILE | 字元裝置 | test -c /dev/tty |
| -g FILE | SGID 位 | test -g /usr/bin/sudo |
| -u FILE | SUID 位 | test -u /usr/bin/passwd |
| -k FILE | Sticky 位 | test -k /tmp |
| -O FILE | 擁有者為當前用戶 | test -O myfile |
| -G FILE | 群組為當前用戶群組 | test -G myfile |
| -N FILE | 自上次讀取後被修改 | test -N ~/.bashrc |
| FILE1 -nt FILE2 | FILE1 比 FILE2 新 | test a.txt -nt b.txt |
| FILE1 -ot FILE2 | FILE1 比 FILE2 舊 | test a.txt -ot b.txt |
| FILE1 -ef FILE2 | 同一 inode (硬連結/同檔) | test a.txt -ef b.txt |
字串比較
| 運算子 | 說明 | 備註 |
| -z STRING | 長度為 0 | 常用:test -z "$VAR" |
| -n STRING | 長度非 0 | 預設行為,可省略 -n |
| STRING1 = STRING2 | 相等 | 單 =,POSIX 標準 |
| STRING1 != STRING2 | 不相等 | |
| STRING1 < STRING2 | 字典序小於 | 需轉義 \< 或用 [[ ]] |
| STRING1 > STRING2 | 字典序大於 | 需轉義 \> 或用 [[ ]] |
整數比較
| 運算子 | 說明 |
| -eq | 等於 |
| -ne | 不等於 |
| -lt | 小於 |
| -le | 小於等於 |
| -gt | 大於 |
| -ge | 大於等於 |
邏輯運算
| 運算子 | 語法 | 優先序 |
| NOT | ! EXPR | 最高 |
| AND | EXPR1 -a EXPR2 | 中 |
| OR | EXPR1 -o EXPR2 | 最低 |
| 群組 | ( EXPR ) | 需轉義 \( \) |
四大判斷結構差異總表
| 特性 | test / [ ] | [[ ]] | (( )) | [[ 字串 ]] |
| 標準 | POSIX | Bash/Zsh/Ksh 擴充 | Bash/Zsh/Ksh 算術 | Bash 擴充 |
| 字串比較 | = != | = != == != =~ (regex) | 不支援 | == != =~ |
| 萬用字元 | 不支援 | 支援 (右邊不加引號) | 不支援 | 支援 |
| 變數引用 | 需雙引號 | 可不加引號 | 直接 $VAR 或 VAR | 可不加引號 |
| 整數比較 | -eq -lt... | -eq -lt... 或 < > <= >= | < > <= >= == != | -eq -lt... |
| 邏輯運算 | -a -o ! | && \|\| ! | && \|\| ! | && \|\| ! |
| 子shell | 否 | 否 | 否 | 否 |
實戰模式
1. 檔案存在性檢查
if [ -e "$CONFIG_FILE" ]; then
echo "配置檔存在"
else
echo "配置檔缺失,使用預設值"
fi
2. 目錄不存在則建立
[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR"
3. 多條件組合
# 檔案存在且可讀且非空
if [ -f "$FILE" -a -r "$FILE" -a -s "$FILE" ]; then
process "$FILE"
fi
# Bash 推薦寫法
if [[ -f "$FILE" && -r "$FILE" && -s "$FILE" ]]; then
process "$FILE"
fi
4. 整數運算與比較
COUNT=10
if (( COUNT > 5 )); then
echo "大於 5"
fi
5. 字串模式比對
VERSION="1.2.3"
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "語義化版本格式正確"
fi
常見錯誤避坑
[ -f $FILE ] → 變數未加引號,空值導致語法錯誤,永用 "$FILE"
[ $A = $B ] → 同理,必加雙引號
[ $A > $B ] → > 被解釋為重導向,必用 [[ $A > $B ]] 或 (( A > B ))
[ -f file -a -r file ] → -a 優先序低,複雜邏輯改用 [[ ]] + &&
熟練掌握 test 系列指令,是撰寫健壯 Shell 腳本的關鍵基礎。