text / yq -- 教學(v4 版) === ###### tags: `OS / Ubuntu / cmd / text` ###### tags: `OS`, `Ubuntu`, `linux`, `command`, `text`, `yq`, `Kubenetes`, `k8s` <br> [TOC] <br> > gpt-5 (2025/10/14) > - 已驗證內容: > - 待驗證內容:all 想用指令列快速讀寫 YAML/JSON?`yq` 就是你的好幫手。以下用 10 分鐘帶你上手,並用 Kubernetes 範例實戰。 --- ## 1) 什麼是 yq? * 一個像 `jq` 一樣的查詢語言,但針對 **YAML**(同時可讀/寫 JSON)。 * 常見用途:讀值、篩選、修改、合併、把 YAML ↔ JSON 互轉。 * 本教學使用 **mikefarah/yq v4** 語法:`yq eval`(縮寫 `yq e`)。 --- ## 2) 安裝 & 基本確認 ```bash # Ubuntu / Debian sudo snap install yq # 版本確認(需 >=4) yq --version ``` --- ## 3) 準備一份練習檔 `hello.yaml` ```yaml= app: name: hello ports: - name: http port: 80 - name: metrics port: 8080 images: backend: ghcr.io/acme/api:1.2.3 frontend: ghcr.io/acme/web:4.5.6 flags: enabled: true replicas: 3 ``` --- ## 4) 最基本的「讀」 ```bash= # 讀出整個檔 yq e '.' hello.yaml # 讀出單一路徑 yq e '.app.name' hello.yaml # => hello # 讀出陣列(全部) yq e '.app.ports' hello.yaml # 讀出第 2 個元素(index 從 0) yq e '.app.ports[1]' hello.yaml # 只要純字串(不加引號):-r / --unwrapScalar yq e -r '.images.backend' hello.yaml ``` --- ## 5) 篩選(select)與 map ```bash= # 找出 name 為 "metrics" 的那個 port 物件 yq e '.app.ports[] | select(.name == "metrics")' hello.yaml # 只取它的 port 數值 yq e '.app.ports[] | select(.name == "metrics") | .port' hello.yaml # => 8080 # 取出所有 ports 的名字(map 為每個元素套表達式) yq e '[.app.ports[].name]' hello.yaml # => - http # - metrics ``` --- ## 6) 更新 / 寫回檔案(in-place) > **小心:會改動檔案!** > 先用不加 `-i` 的方式看結果再決定是否寫回。 ```bash # 改一個標量值 yq e -i '.flags.replicas = 5' hello.yaml # 新增路徑(不存在會自動建立) yq e -i '.flags.strategy = "RollingUpdate"' hello.yaml # 陣列追加一個元素 yq e -i '.app.ports += [{"name":"admin","port":9000}]' hello.yaml # 刪除一個欄位 yq e -i 'del(.images.frontend)' hello.yaml ``` --- ## 7) YAML/JSON 互轉 & from-env ```bash # YAML → JSON yq e -o=json '.' hello.yaml # JSON → YAML(指定輸入解析器) cat data.json | yq e -p=json '.' # 由環境變數帶入 export NEW_TAG="2.0.0" yq e -i '.images.backend = "ghcr.io/acme/api:" + env(NEW_TAG)' hello.yaml ``` --- ## 8) 多文件 YAML(---)與 eval-all ```bash # 只取第 2 份文件(從 0 起算) kubectl get deploy myapp -o yaml \ | yq e 'select(documentIndex == 1)' - # 多檔合併(簡單覆蓋:右邊覆蓋左邊) # values-base.yaml 與 values-prod.yaml 合併 yq ea '. as $doc ireduce ({}; . * $doc)' values-base.yaml values-prod.yaml ``` > `ea` = `eval-all`:針對所有輸入文件/文件片段一起處理。 > 運算子 `*` 是 **合併覆蓋**(右邊蓋左邊)。`*+` 則是「保留左邊、缺的再補」。 --- ## 9) 與 kubectl 串接(K8s 實戰) ### 9.1 取得 Service ports 中 name=metrics(你的原需求) ```bash kubectl -n slurm get service \ -l app.kubernetes.io/instance=slurm-exporter,app.kubernetes.io/name=slurm-exporter \ -o yaml \ | yq e '.items[].spec.ports[] | select(.name == "metrics")' ``` 只印出數值: ```bash # 只印名字 ... | yq e -r '.items[].spec.ports[] | select(.name == "metrics") | .name' # 只印 port ... | yq e '.items[].spec.ports[] | select(.name == "metrics") | .port' ``` ### 9.2 取得 Deployment 的第一個 container image ```bash kubectl -n default get deploy myapp -o yaml \ | yq e -r '.spec.template.spec.containers[0].image' ``` ### 9.3 更新 YAML 清單後再套用 ```bash # 將 replicas 改為 4 再 apply(不改原檔) kubectl -n default get deploy myapp -o yaml \ | yq e '.spec.replicas = 4' - \ | kubectl apply -f - ``` --- ## 10) 常見陷阱 / 小提醒 1. **版本差異** * v3 的 `yq r/w/m` 語法和 v4 完全不同;本教學為 **v4**。 * 若你看到 `yq r file.yaml path.to.key` 那是 **v3** 舊語法。 2. **`-r` 的意思** * 在 v4 中等於 `--unwrapScalar`:輸出純量時不加引號,適合管線接到其他工具。 3. **陣列索引從 0 起算** * `.items[0]` 是第一個;`.items[]` 是展開全部元素。 4. **stdin 記得用 `-`** * 例如 `cat x.yaml | yq e '.a' -` 5. **寫入風險** * `-i` 會改檔案,先試跑不加 `-i` 看輸出,再決定是否寫回。 --- ## 11) 迷你速查表(Cheat Sheet) ```bash # 讀值 yq e '.path.to.key' file.yaml # 篩選(select) yq e '.list[] | select(.name == "metrics")' file.yaml # 只輸出純字串 yq e -r '.images.backend' file.yaml # 新增/修改(寫回) yq e -i '.flags.enabled = true' file.yaml # 刪除 yq e -i 'del(.flags.strategy)' file.yaml # 陣列追加 yq e -i '.list += ["new-item"]' file.yaml # YAML → JSON yq e -o=json '.' file.yaml # JSON → YAML cat x.json | yq e -p=json '.' # 多檔合併(右覆蓋左) yq ea '. as $d ireduce ({}; . * $d)' a.yaml b.yaml # 只取多文件 YAML 的第 N 份 yq e 'select(documentIndex == N)' file.yaml ``` --- ## 12) 小練習(動手做) 1. 在 `hello.yaml` 把 `flags.replicas` 改為 10。 2. 追加一個 `app.ports`:`name: grpc, port: 9090`。 3. 刪除 `images.frontend`。 4. 把整份 YAML 轉成 JSON 輸出。 5. 用 `kubectl get service ... -o yaml | yq` 只印出 name=metrics 的 `targetPort`。 <br> {%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up