Install & quick start
YAML.sh ships as one executable text file. The released file contains both the portable shell launcher and the AWK engine.
Install the release
The hosted installer downloads the release artifact, verifies its pinned SHA-256 digest, then writes it to the install directory:
curl -fsSL https://yaml.azohra.com/install | sh
Choose another destination without sudo:
curl -fsSL https://yaml.azohra.com/install | YSH_INSTALL_DIR="$HOME/.local/bin" sh
Requirements
- A POSIX-style
/bin/sh. - A compatible AWK implementation.
The release suite covers macOS AWK, mawk, original AWK, POSIX-mode gawk, and BusyBox AWK across several POSIX shells. Bash, Python, Ruby, Node.js, Go, jq, and a package manager are not runtime requirements.
First query
Given config.yml:
server:
host: localhost
ports: [8080, 8443]
services:
- name: api
enabled: true
Select a scalar:
ysh '.server.host' config.yml
# localhost
Select a sequence item:
ysh '.server.ports[1]' config.yml
# 8443
Select a collection:
ysh '.services[0]' config.yml
# {"name":"api","enabled":true}
Stream and filter nodes:
ysh '.services[] | select(.enabled) | .name' config.yml
# api
Use a default when a path is missing, null, or false:
ysh '.release.channel // "stable"' config.yml
# stable
Slice and label a result:
ysh '"\(.server.host):\(.server.ports[0:2] | length)"' config.yml
# localhost:2
Transform and emit YAML:
ysh -o=yaml '.release.channel = "stable"' config.yml
Once the result looks right, update the file in place:
ysh -i '.release.channel = "stable"' config.yml
In-place output is atomic and preserves file permissions. Common replacements, inserts, deletes, and sequence reorders retain comments, blank lines, directives, properties, block/flow layout, and quote style. Unsupported presentation edits fall back to stable semantic YAML—review the diff like the tiny chaos engineer you are.
The same expression can update several files as one preflighted transaction:
ysh -i '.release.channel = "stable"' services/*.yml
Bound hostile input
Defaults are generous; automation can tighten them:
ysh --max-input-bytes 1048576 --max-nodes 20000 --max-depth 64 '.' config.yml
Standard input
Omit the file to read YAML from standard input:
printf '%s\n' 'answer: 42' | ysh '.answer'
Use - explicitly when it helps a generated command read clearly:
generate-config | ysh '.release.version' -
Compose configuration
Environment values can stay strings or be parsed as YAML:
IMAGE_TAG=stable ysh '.image.tag = strenv(IMAGE_TAG)' deploy.yml
LIMITS='{cpu: 2, memory: 1Gi}' ysh '.resources = env(LIMITS)' deploy.yml
Evaluate files independently by listing them, or evaluate one expression across the combined document stream:
ysh '[filename, .name]' one.yml two.yml
ysh eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' defaults.yml production.yml
Next steps
- Learn paths, streams, construction, and updates
- Choose value, JSON, YAML, type, tag, or line output
- Read the YAML support contract
- Compare the focused surface with yq
Maintaining a script written for the original command interface? Use the focused legacy migration guide.