yq — YAML Processing

Advanced yq patterns for infrastructure work — reading Antora attributes, filtering by key/value patterns, formatting transforms, and credential safety practices. Uses jq-compatible syntax for YAML files.

Reading YAML

Top-level keys
yq 'keys' docs/antora.yml
# Output:
# [
#   "asciidoc",
#   "name",
#   "nav",
#   "start_page",
#   "title",
#   "version"
# ]
Scalar values
yq '.name, .version' docs/antora.yml
# Output:
# "captures"
# null
Nested access — specific attribute
yq '.asciidoc.attributes["mail-hostname"]' docs/antora.yml
# Output: "mail-01.inside.domusdigitalis.dev"
Count entries
yq '.asciidoc.attributes | length' docs/antora.yml
# Output: 134
List all attribute keys
yq '.asciidoc.attributes | keys' docs/antora.yml | head -15
# Output:
# [
#   "ad-dc-hostname",
#   "ad-dc-ip",
#   "attribute-missing",
#   "author",
#   "bind-ip",
#   "bt-buds-mac",
#   ...
Array access — nav sources
yq '.nav[]' docs/antora.yml
# Output: "modules/ROOT/nav.adoc"

Filtering and Transforms

Filter attributes by key pattern
yq '.asciidoc.attributes | to_entries | map(select(.key | test("^port-")))' docs/antora.yml
# Output:
# [
#   {"key": "port-https", "value": "443"},
#   {"key": "port-ssh", "value": "22"},
#   {"key": "port-kerberos", "value": "88"},
#   {"key": "port-ldap", "value": "389"},
#   {"key": "port-ldaps", "value": "636"},
#   {"key": "port-dns", "value": "53"},
#   {"key": "port-dhcp-server", "value": "67"},
#   {"key": "port-dhcp-client", "value": "68"},
#   {"key": "port-ntp", "value": "123"},
#   {"key": "port-smtp", "value": "25"},
#   {"key": "port-submission", "value": "587"},
#   {"key": "port-imaps", "value": "993"}
# ]
Format as key=value pairs
yq -r '.asciidoc.attributes | to_entries[] | select(.key | test("^ws-")) | "\(.key) = \(.value)"' docs/antora.yml
# Output:
# ws-razer-hostname = modestus-razer.inside.domusdigitalis.dev
# ws-razer-short = modestus-razer
Filter attributes by value pattern
yq -r '.asciidoc.attributes | to_entries[] | select(.value | test("10\\.50\\.")) | "\(.key): \(.value)"' docs/antora.yml
# Lists all attributes containing IP addresses
Count by pattern — how many port attributes?
yq '.asciidoc.attributes | to_entries | map(select(.key | test("^port-"))) | length' docs/antora.yml
# Output: 12

Gotchas

Dotted keys — bracket notation required
# WRONG — yq interprets dots as path separators
yq '.hosts.gitlab.com.token' file.yml
# Navigates: hosts → gitlab → com → token (wrong path)

# CORRECT — bracket notation for dotted keys
yq '.hosts["gitlab.com"].token' file.yml
!!null tag — silently overrides values
# In YAML, !!null means explicit null
# key: !!null  ← this is NOT the same as key being absent
# Watch for this in glab/gh config files

# Check for null values
yq '.[] | select(. == null)' file.yml
yq vs jq — similar but not identical
# yq uses jq-compatible syntax for most operations
# But YAML-specific features differ:
yq '.key' file.yml        # works
yq '.key' file.json       # also works — yq reads JSON too

# jq does NOT read YAML
jq '.key' file.yml         # Error: parse error
Credential safety — inspect keys only
# NEVER dump full credential files
# WRONG
yq '.' ~/.config/gh/hosts.yml

# CORRECT — keys only
yq 'keys' ~/.config/gh/hosts.yml

# Test path syntax on safe fields first
yq -r '.git_protocol' ~/.config/gh/hosts.yml
String vs number — YAML autodetects types
# YAML: port: 443   → number (443)
# YAML: port: '443' → string ("443")
# antora.yml uses quoted strings for ports to prevent YAML type coercion
# Always quote port values in antora.yml

See Also

  • jq — JSON counterpart (identical syntax)

  • jq Text Processing — fundamentals shared by both tools