用 Bash 解析 YAML 設定
在 Linux 系統管理與自動化腳本開發中,我們經常需要讀取外部設定檔。雖然 JSON 和 INI 格式在 Shell 中處理相對容易,但 YAML 因其可讀性高、支援巢狀結構及註解功能,成為現代配置管理(如 Kubernetes、Ansible、GitHub Actions)的首選格式。
許多初學者會試圖用正規表示式(Regex)去解析 YAML,這不僅脆弱且難以維護。本文將介紹如何在 Bash 中優雅且穩定地解析 YAML 檔案,特別是在 Ubuntu 22.04 或 Debian 12 環境下的最佳實踐。
為什麼不推薦用純 Bash 解析 YAML?
YAML 的語法複雜,包含縮排、字串、數字、布林值、列表等多種資料型別,且對空白字元極度敏感。試圖用 grep 或 awk 硬解,往往會遇到邊緣案例(Edge Cases)導致解析失敗。因此,我們的策略是:利用現有的輕量級工具,將 YAML 轉換為 Shell 易於處理的格式(如 JSON 或 Key-Value 對)。
方法一:使用 yq 工具(推薦)
yq 是目前最流行的 YAML 處理工具,其語法類似 jq,功能強大且直觀。在 Ubuntu 22.04 / Debian 12 上,我們可以透過 snap 或下載二進位檔來安裝。
安裝 yq
# 安裝 yq (使用 snap 方式,最簡單)
sudo snap install yq
# 或者下載最新版本的二進位檔
# curl -sL https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -o /usr/local/bin/yq
# chmod +x /usr/local/bin/yq
實際操作範例
假設我們有一個 config.yaml 檔案:
database:
host: localhost
port: 5432
credentials:
username: admin
password: "s3cr3t!"
app:
debug: true
features:
- logging
- monitoring
1. 讀取單一值
要獲取資料庫的連接埠,可以使用以下指令:
yq '.database.port' config.yaml
# 輸出: 5432
若要將結果直接賦值給 Bash 變數,記得使用 $(...):
DB_PORT=$(yq '.database.port' config.yaml)
echo "Database Port: $DB_PORT"
2. 讀取巢狀值與特殊字元
密碼中包含特殊字元時,yq 會自動處理引號。若要獲取完整的路徑值:
DB_PASS=$(yq '.database.credentials.password' config.yaml)
echo "Password: $DB_PASS"
3. 遍歷列表
若要處理 features 列表,可以結合 yq 的輸出與 while read:
yq '.app.features[]' config.yaml | while read feature; do
echo "Enabled feature: $feature"
done
輸出結果:
Enabled feature: logging
Enabled feature: monitoring
方法二:轉換為 JSON 後使用 jq
如果你已經熟悉 jq,或者系統環境不允許安裝 yq,可以將 YAML 轉換為 JSON 後再處理。這在 CI/CD 管道中非常常見。
# 安裝 jq (若尚未安裝)
sudo apt-get install -y jq
# 將 YAML 轉為 JSON 並存入變數
JSON_DATA=$(yq -o=json config.yaml)
# 使用 jq 提取數據
echo "$JSON_DATA" | jq '.database.host'
此方法的優點在於 jq 的生態系極其豐富,適合複雜的資料轉換邏輯。
常見問題與解決方案
1. 數值被誤判為字串?
YAML 規範中,某些數字(如 01 或 1e2)可能被解析為字串。在 Bash 中進行數值比較時,請務必確認變數類型。
解決方案:
使用 yq 的 @n 過濾器強制輸出為數字,或在 Bash 中使用 (( )) 進行算術擴展:
# 強制輸出為數字
PORT=$(yq '.database.port | @n' config.yaml)
# 在 Bash 中進行比較
if (( PORT > 1000 )); then
echo "Port is valid"
fi
2. 處理包含冒號的字串值?
YAML 中若值包含冒號(如 URL http://example.com),直接解析有時會出錯。
解決方案:
確保該值在 YAML 檔案中已用雙引號或單引號包裹。yq 通常能自動處理,但若遇到問題,可檢查原始 YAML 格式:
# 正確寫法
url: "http://example.com:8080/path"
若腳本中需要動態插入包含冒號的值,建議使用 yq 的 eval-all 模式或預先轉義。
小結
在 Bash 中解析 YAML,最佳實踐是避免手動解析,而是借助 yq 或 jq 等專門工具。yq 提供了直觀的查詢語法,極大地簡化了配置讀取的複雜度。對於 Ubuntu 22.04 和 Debian 12 使用者,建議優先安裝 yq,它不僅輕量,還能無縫整合到現有的 Shell 腳本工作流中。
透過本文的範例,你可以輕鬆地將 YAML 設定值讀入 Bash 變數,並進行後續的邏輯判斷與自動化操作。掌握這些技巧,將大幅提升你的系統管理效率。