Bash 陷阱與常見錯誤的解決方法
Shell 腳本雖然是 Linux 系統管理的利器,但對於初學者甚至經驗豐富的開發者來說,Bash 的語法特性往往潛藏著許多不易察覺的陷阱。一個小小的引號遺漏或變數展開錯誤,就可能導致資料遺失或資安漏洞。本文將針對 Ubuntu 22.04 與 Debian 12 環境,剖析幾個最常見的 Bash 陷阱,並提供實用的解決方案與完整範例。
陷阱一:未加引號的變數展開導致字詞拆分
這是 Bash 新手最常犯錯的地方。當變數內容包含空格時,若未使用雙引號包圍,Bash 會根據內部欄位分隔符號(IFS,預設為空格、跳脫字元、換行符號)將變數拆分成多個參數,進而導致指令行為異常。
錯誤示範: 假設我們有一個檔案路徑包含空格:
filename="my document.txt"
# 危險!Bash 會將其視為兩個參數:my 和 document.txt
cp $filename /tmp/
上述指令實際上執行的是 cp my document.txt /tmp/,這通常會導致 cp 指令報錯,因為它誤以為要複製檔案 my 到目錄 document.txt,而 document.txt 被視為額外參數或目標目錄。
正確做法: 務必使用雙引號將變數包起來,強制 Bash 將其視為單一參數:
filename="my document.txt"
# 正確!變數內容保持完整
cp "$filename" /tmp/
陷阱二:判斷式中的邏輯運算符誤用
在 Bash 的 [ (test) 或 [[ 指令中,邏輯「與」和「或」的寫法與 C 語言或 Python 不同。許多使用者習慣使用 && 或 || 作為判斷條件內的邏輯運算,這在 [ 中是無效的,甚至會導致語法錯誤。
錯誤示範:
age=25
# 錯誤!在 [ ] 內使用 && 會導致語法錯誤或意外行為
if [ $age -gt 18 && $age -lt 60 ]; then
echo "Adult"
fi
正確做法:
使用 -a (and) 和 -o (or) 運算符,或者更推薦使用 [[ ]] 並結合 && 和 ||,因為 [[ ]] 提供了更強大的模式匹配與邏輯運算支援:
age=25
# 推薦寫法:使用 [[ ]] 結合 &&
if [[ $age -gt 18 && $age -lt 60 ]]; then
echo "Adult"
fi
# 傳統寫法:使用 [ ] 結合 -a
if [ $age -gt 18 -a $age -lt 60 ]; then
echo "Adult"
fi
實用範例:安全處理檔案路徑與條件判斷
以下是一個完整可執行的 Bash 腳本,示範如何安全地處理包含空格的檔案路徑,並結合正確的條件判斷邏輯。此腳本會檢查指定目錄是否存在,並列出其中所有 .txt 檔案的大小。
#!/bin/bash
# 設定目標目錄,包含空格以測試變數展開安全性
target_dir="/tmp/my test dir"
txt_pattern="*.txt"
# 1. 檢查目錄是否存在(使用 [[ ]] 確保安全性)
if [[ -d "$target_dir" ]]; then
echo "目錄存在:$target_dir"
else
echo "目錄不存在,正在建立..."
mkdir -p "$target_dir"
fi
# 2. 在目錄中尋找 .txt 檔案
# 注意:使用 find 指令並搭配 -print0 處理特殊字元,避免管道錯誤
file_count=$(find "$target_dir" -maxdepth 1 -type f -name "$txt_pattern" | wc -l)
# 3. 條件判斷:檔案數量大於 0 且小於 10
if [[ $file_count -gt 0 && $file_count -lt 10 ]]; then
echo "找到 $file_count 個 .txt 檔案:"
# 使用 while read 迴圈安全處理每行路徑
find "$target_dir" -maxdepth 1 -type f -name "$txt_pattern" -print0 | while IFS= read -r -d '' file; do
# 獲取檔案大小(單位:位元組)
file_size=$(stat -c %s "$file")
# 獲取檔案修改時間
file_mtime=$(stat -c %y "$file")
echo " - 檔案:$file"
echo " 大小:${file_size} bytes"
echo " 修改時間:$file_mtime"
done
else
echo "檔案數量不符合條件 ($file_count)"
fi
echo "腳本執行完畢。"
常見問題與解法
問題一:腳本執行時出現「Permission denied」
原因: Bash 腳本預設不會自動賦予執行權限。
解法: 使用 chmod 賦予執行權限:
chmod +x script.sh
./script.sh
問題二:變數內容出現意外換行或空格被截斷
原因: 未正確設定 IFS 或使用 read 指令時未指定 -r 參數。
解法: 在使用 read 讀取檔案內容時,務必加上 -r 以避免反斜線被解譯,並使用 -d '' 配合 find -print0 處理包含換行符號的檔名:
# 正確讀取含特殊字元的檔名
find . -type f -print0 | while IFS= read -r -d '' file; do
echo "$file"
done
小結
Bash 腳本的強大之處在於其靈活性,但這種靈活性也伴隨著潛在的風險。透過始終使用雙引號包圍變數、正確使用 [[ ]] 進行條件判斷,以及善用 find 配合 -print0 處理特殊檔案名,可以大幅減少腳本執行時的錯誤。建議在撰寫複雜腳本時,使用 bash -n script.sh 進行語法檢查,並在測試環境中充分驗證,以確保腳本在 Ubuntu 22.04 或 Debian 12 等現代 Linux 發行版上的穩定性與安全性。