用 Bash 解析 YAML 設定 文章首圖

用 Bash 解析 YAML 設定

用 Bash 解析 YAML 設定

在 Linux 系統管理與自動化腳本開發中,我們經常需要讀取外部設定檔。雖然 JSON 和 INI 格式在 Shell 中處理相對容易,但 YAML 因其可讀性高、支援巢狀結構及註解功能,成為現代配置管理(如 Kubernetes、Ansible、GitHub Actions)的首選格式。

許多初學者會試圖用正規表示式(Regex)去解析 YAML,這不僅脆弱且難以維護。本文將介紹如何在 Bash 中優雅且穩定地解析 YAML 檔案,特別是在 Ubuntu 22.04 或 Debian 12 環境下的最佳實踐。

為什麼不推薦用純 Bash 解析 YAML?

YAML 的語法複雜,包含縮排、字串、數字、布林值、列表等多種資料型別,且對空白字元極度敏感。試圖用 grepawk 硬解,往往會遇到邊緣案例(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 規範中,某些數字(如 011e2)可能被解析為字串。在 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"

若腳本中需要動態插入包含冒號的值,建議使用 yqeval-all 模式或預先轉義。

小結

在 Bash 中解析 YAML,最佳實踐是避免手動解析,而是借助 yqjq 等專門工具。yq 提供了直觀的查詢語法,極大地簡化了配置讀取的複雜度。對於 Ubuntu 22.04 和 Debian 12 使用者,建議優先安裝 yq,它不僅輕量,還能無縫整合到現有的 Shell 腳本工作流中。

透過本文的範例,你可以輕鬆地將 YAML 設定值讀入 Bash 變數,並進行後續的邏輯判斷與自動化操作。掌握這些技巧,將大幅提升你的系統管理效率。