← Весь справочник

yq

Чтение и правка YAML в стиле jq — выборка, select, правка на месте, слияние файлов, конвертация в JSON

yq (версия mikefarah, v4) — это jq для YAML: тот же язык выражений, но читает и пишет YAML, а ещё JSON, XML, TOML, CSV, properties. Главные отличия от jq — умеет править файл на месте (-i) и сохраняет комментарии и форматирование.

Синтаксис

yq [опции] 'выражение' [файл…]
yq eval 'выражение' файл           # то же самое: eval (e) — команда по умолчанию
yq eval-all 'выражение' файл…      # (ea) все файлы и документы сразу, одним потоком

Без файла читает stdin. Выражение бери в одинарные кавычки.

Опции

ОпцияЧто делает
-iзаписать результат обратно в (первый) файл
-o=ФОРМАТформат вывода: yaml, json, xml, props, csv, tsv, shell (вывод в TOML в v4.44 поддерживается только для простых значений)
-p=ФОРМАТформат входа: yaml, json, xml, props, csv, tsv, toml; по умолчанию угадывается по расширению
-I=Nотступ; -o=json -I=0 — JSON в одну строку
-P«красивый» YAML: блочный стиль вместо {…} и […]
-rпечатать строки без кавычек и комментариев — включено по умолчанию для YAML; -r=false — выключить
-eкод выхода 1, если результат null, false или ничего не найдено
-nне читать вход — создать документ с нуля
-Nне печатать разделители документов ---
-C / -Mпринудительно включить / выключить цвет
--from-file файлвзять выражение из файла
-f extractработать с YAML-шапкой (front matter) markdown-файла
-s 'выражение'разложить результаты по файлам, имя файла — из выражения

Флагов --arg, как у jq, нет: значения из оболочки передавай через окружение (strenv, env).

Пути и выборка

ВыражениеЧто делает
.a.b, .a[0], .a[-1], .a[]поле, элемент, последний, все элементы
.["a.b"]ключ с точкой или спецсимволами
..рекурсивно все узлы
select(.name == "x")отбор по условию; есть and, or, not
has("k"), keys, lengthналичие ключа, список ключей, длина
tagтип узла: !!str, !!int, !!bool, !!map, !!seq, !!null
path, key, parentпуть к узлу, его ключ или индекс, родительский узел
a // bb, если a — null, false или ничего
select(di == 1)второй документ из файла с несколькими --- (di = document_index)

Изменение

ВыражениеЧто делает
.a = "v"присвоить; промежуточные ключи создаются сами
.a |= fобновить значение через выражение: .name |= upcase
(… | select(…) | .f) = "v"изменить поле только у подходящих элементов, сохранив весь документ
.list += ["x"]дописать в массив
del(.a) / del(.list[] | select(…))удалить поле / подходящие элементы
. * {"a": 1}глубокое слияние объектов (правый перекрывает левый); *+ — массивы склеиваются
.a style="double"стиль записи значения: double, single, literal (|), folded (>), flow
... comments = ""убрать все комментарии
explode(.)раскрыть якоря и ссылки (&a, *a, <<:)
sort_keys(..)отсортировать ключи на всех уровнях

Функции

ФункцииЧто делают
strenv(VAR) / env(VAR)значение переменной окружения: всегда строкой / с разбором типа
envsubstподставить ${VAR} внутри строки
load("файл")загрузить другой YAML-файл
map(f), to_entries, from_entries, with_entries(f)как в jq
sort, sort_by(f), unique, group_by(f), reverseсортировка и группировка
split(s), join(s), upcase, downcase, test(re), sub(re; s)строки и регулярки
line_comment, head_comment, foot_commentпрочитать или задать комментарий узла
@json, @yaml, @base64, @base64dзакодировать значение в строку другого формата

Примеры

cat > app.yaml <<'EOF'
app:
  name: demo
  replicas: 2
  env:
    - name: MODE
      value: dev
EOF

# прочитать значение
yq '.app.replicas' app.yaml

# найти элемент списка по полю
yq '.app.env[] | select(.name == "MODE") | .value' app.yaml

# показать изменение, не трогая файл
yq '.app.replicas = 3' app.yaml

# изменить на месте
yq -i '.app.replicas = 3' app.yaml

# поменять значение у конкретного элемента списка
yq -i '(.app.env[] | select(.name == "MODE") | .value) = "test"' app.yaml

# добавить вложенное поле — промежуточные ключи создадутся сами
yq -i '.app.labels.tier = "web"' app.yaml

# значение из переменной окружения как строку
NAME=demo2 yq '.app.name = strenv(NAME)' app.yaml

# YAML → JSON и дальше в jq
yq -o=json '.app' app.yaml | jq -r '.name'

# JSON → YAML
echo '{"k":[1,2]}' | yq -p=json -o=yaml

# слить два файла: значения из override.yaml перекрывают base.yaml
yq ea '. as $item ireduce ({}; . * $item)' base.yaml override.yaml

# все значения плоским списком «путь = значение»
yq -o=props app.yaml

# создать документ с нуля
yq -n '.server.port = 8080'

Подводные камни

  • Есть два разных yq. Python-версия (kislyuk/yq) — обёртка над jq с другими флагами (например, -y для вывода YAML) и без сохранения комментариев. Проверь yq --version: нужна строка mikefarah/yq … v4.
  • Без -i файл не меняется — результат просто печатается. А yq '…' f.yaml > f.yaml обнулит файл, как и с любой командой.
  • Присваивание после | меняет весь документ. .app.env[] | select(…) | .value = "x" выведет только выбранные элементы. Чтобы получить весь файл с правкой, бери левую часть в скобки: (… | .value) = "x".
  • Типы важны. .version = 1.10 запишет число, а .version = "1.10" — строку. Для значений из окружения: strenv() всегда даёт строку, env() разбирает тип (5 станет числом).
  • Несуществующий путь даёт null, а не ошибку. Для проверок добавляй -e.
  • Несколько документов в файле. Выражение применяется к каждому документу отдельно, вывод разделяется ---. Чтобы работать с ними вместе (собрать в массив, слить), нужен eval-all.
  • * сливает словари, но массивы заменяет целиком. Чтобы склеить списки, используй *+.
  • Строку "false" в кавычках YAML считает строкой, а false без кавычек — булевым значением; то же с yes/no, on/off в YAML 1.1-парсерах других программ. Если значение должно остаться строкой, держи кавычки.

См. также

jq · kubectl · ansible · docker-compose · gitlab-ci