---
# System prepended metadata

title: text / yq -- 教學（v4 版）
tags: [linux, OS / Ubuntu / cmd / text, OS, text, k8s, command, Ubuntu, yq, Kubenetes]

---

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 %}
