Turn a shell loop into a JSON array with jo, jq's inverse
jq is unbeatable for tearing JSON apart; jo is the boring, forgotten tool for building it back up. Each `jo key=value ...` call emits one type-aware JSON object (numbers and booleans auto-detected, no manual quoting), so a plain shell for-loop becomes a stream of JSON records ready to slurp, sort, and filter with jq — no printf/sed JSON-escaping gymnastics.
Setup
- → apt install jo # or: brew install jo
Cost per run
free
The one-liner
$ for f in *; do [ -f "$f" ] && jo name="$f" bytes=$(stat -c%s "$f"); done | jq -s '.' | jq 'sort_by(-.bytes) | .[0:5]'What each stage does
- [01] jo
for f in *; do [ -f "$f" ] && jo name="$f" bytes=$(stat -c%s "$f"); doneLoop the current directory's entries and emit one compact JSON object per regular file — `bytes=$(stat -c%s "$f")` is auto-detected as a JSON number, not a quoted string, with zero manual escaping. - [02] jq
jq -s '.'Slurp the newline-delimited stream of single objects into one JSON array — the hand-off point from shell-native construction to normal jq querying. - [03] jq
jq 'sort_by(-.bytes) | .[0:5]'Rank by size descending and keep the top 5 — the same array can just as easily be grouped, filtered, or POSTed to an API as a JSON body.
Expected output (sample)
[
{
"name": "README.md",
"bytes": 10537
},
{
"name": "deno.json",
"bytes": 1629
},
{
"name": "vite.config.ts",
"bytes": 854
},
{
"name": "playwright.config.ts",
"bytes": 808
},
{
"name": "main.ts",
"bytes": 416
}
]Caveats & tips
- Verified on jo 1.9 (apt, Debian/Ubuntu package), run for real against oneliner101/'s own top-level *.json/*.ts/*.md files — output above is the real, unmodified stdout.
- This apt build auto-detects numbers/booleans from bare `key=value` (no `:=` operator support) — `count=5` is already a JSON number; check `jo --help`/`jo -v` on your platform since jpmens/jo upstream and distro packages have drifted.
- The same `jo ... | curl -d @- ...` shape replaces here-doc JSON bodies for webhook/API POSTs built from shell variables — the loop above is one instance of a more general pattern.
- For deeply nested output, `jo -p` pretty-prints and `jo -a` wraps args directly into an array without the jq -s slurp step.