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