{"id":41277611,"url":"https://github.com/fedir/json_encode","last_synced_at":"2026-06-05T00:01:20.057Z","repository":{"id":57575992,"uuid":"120674857","full_name":"fedir/json_encode","owner":"fedir","description":"Simple JSON encoder for usage in shell. Could by handy for sysadmins / devops / developers.","archived":false,"fork":false,"pushed_at":"2026-06-04T22:58:56.000Z","size":60,"stargazers_count":24,"open_issues_count":0,"forks_count":7,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-06-04T23:09:28.979Z","etag":null,"topics":["bash","encoding","go","golang","json","shell"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fedir.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"patreon":"fedir"}},"created_at":"2018-02-07T21:36:52.000Z","updated_at":"2026-06-04T22:59:32.000Z","dependencies_parsed_at":"2022-08-29T00:50:55.599Z","dependency_job_id":null,"html_url":"https://github.com/fedir/json_encode","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/fedir/json_encode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedir%2Fjson_encode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedir%2Fjson_encode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedir%2Fjson_encode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedir%2Fjson_encode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fedir","download_url":"https://codeload.github.com/fedir/json_encode/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fedir%2Fjson_encode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33924832,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-04T02:00:06.755Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","encoding","go","golang","json","shell"],"created_at":"2026-01-23T02:43:35.810Z","updated_at":"2026-06-05T00:01:20.051Z","avatar_url":"https://github.com/fedir.png","language":"Go","funding_links":["https://patreon.com/fedir"],"categories":[],"sub_categories":[],"readme":"# json_encode for shell\n\n[![CI](https://github.com/fedir/json_encode/actions/workflows/ci.yml/badge.svg)](https://github.com/fedir/json_encode/actions/workflows/ci.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/fedir/json_encode)](https://goreportcard.com/report/github.com/fedir/json_encode)\n[![GoDoc](https://godoc.org/github.com/fedir/json_encode?status.svg)](https://godoc.org/github.com/fedir/json_encode)\n[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n\nTurn any shell output into JSON — one pipe away.\n\nBuilt for sysadmins, DevOps and developers who need to feed shell data into APIs,\nmonitoring systems, ELK, dashboards or `jq` pipelines. It tries to **just work**:\nnumbers become numbers, whitespace columns split themselves, and output is\npretty-printed and colorized on a terminal but compact when piped.\n\n![json_encode in action](demo/json_encode.gif)\n\n\u003csub\u003eDemo recorded with [VHS](https://github.com/charmbracelet/vhs) — regenerate with `make demo` (script: [`demo/demo.tape`](demo/demo.tape)).\u003c/sub\u003e\n\n```bash\n$ printf 'host db.internal\\nport 5432\\n' | json_encode -k\n{\n  \"host\": \"db.internal\",\n  \"port\": 5432\n}\n$ printf 'host db.internal\\nport 5432\\n' | json_encode -k | cat\n{\"host\":\"db.internal\",\"port\":5432}\n```\n\n## Installation\n\n**Go install** (requires Go 1.16+):\n\n```bash\ngo install github.com/fedir/json_encode@latest\n```\n\n**Homebrew:**\n\n```bash\nbrew install fedir/tap/json_encode\n```\n\n**Pre-built binaries** — grab one for your OS/arch from the\n[releases page](https://github.com/fedir/json_encode/releases).\n\n**From source:**\n\n```bash\ngit clone https://github.com/fedir/json_encode.git\ncd json_encode\nmake build\ncp json_encode /usr/local/bin/\n```\n\n## Arguments\n\nEvery flag has a short and a long form. With no file arguments, input is read from\nstdin.\n\n| Flag | Description |\n|------|-------------|\n| `-c, --columns` | Split each line into fields → **array of arrays** |\n| `-n, --names a,b,c` | Split and emit an **array of objects** with these keys |\n| `-H, --header` | Split; the **first row supplies the keys** |\n| `-k, --kv` | **Object** `{first field: remainder}` |\n| `--csv` / `--tsv` | Parse as CSV/TSV (quoted fields honoured); with `-H` → objects |\n| `-d, --delimiter STR` | Field separator (default: **runs of whitespace**, awk-style) |\n| `-f, --fields LIST` | Keep 1-based fields; supports ranges, e.g. `1-3,7` |\n| `-0, --null` | Read NUL-delimited input (`find -print0`) |\n| `-p, --pretty` | Force pretty (multi-line) |\n| `--compact` | Force compact (single line) |\n| `--color MODE` | `auto` (default) / `always` / `never` (also `--no-color`) |\n| `--raw` | Keep every value a string (disable type inference) |\n| `-l, --jsonl` | Newline-delimited JSON, one value per line |\n| `-F, --follow` | Stream line-by-line as input arrives (`tail -f`) |\n| `-o, --output FILE` | Write to FILE instead of stdout |\n| `--wrap` | Wrap output in `{host, timestamp, data}` |\n| `-V, --version` | Print version and exit |\n| `-h, --help` | Show help |\n\n**Smart defaults:**\n\n- **Type inference is on.** Values that round-trip exactly become real JSON\n  numbers / booleans / `null`; anything ambiguous stays a string, so leading-zero\n  IDs (`007`), versions (`1.2.3`), IPs and times are preserved. Use `--raw` to keep\n  everything as strings.\n- **Splitting defaults to whitespace runs** (awk-style), so `ps`/`df`/`free` output\n  needs no `tr -s`. Pass `-d` for a literal delimiter.\n- **Output adapts to the terminal:** pretty + color when stdout is a TTY, compact\n  and uncolored when piped or redirected. Override with `-p`, `--compact`, `--color`.\n\n**Mode precedence:** `-k` → `-H`/`-n` (objects) → `-c`/`--csv`/`--tsv` (columns) → lines.\n\n## Basic usage\n\n**Lines → JSON array** (numbers are typed)\n\n```bash\nseq 1 5 | json_encode\n[1,2,3,4,5]\n```\n\n**Columns → array of arrays** (`-c`, whitespace split by default)\n\n```bash\necho -e \"alice 30\\nbob 25\" | json_encode -c\n[[\"alice\",30],[\"bob\",25]]\n```\n\n**Key-value → JSON object** (`-k`)\n\n```bash\necho -e \"host db.internal\\nport 5432\" | json_encode -k\n{\"host\":\"db.internal\",\"port\":5432}\n```\n\n**Named columns → array of objects** (`-n` / `-H`)\n\n```bash\necho -e \"alice 30\\nbob 25\" | json_encode -n name,age\n[{\"age\":30,\"name\":\"alice\"},{\"age\":25,\"name\":\"bob\"}]\n\n# or let the data name itself from a header row\nps -eo pid,comm | json_encode -H\n[{\"COMMAND\":\"systemd\",\"PID\":1},{\"COMMAND\":\"sshd\",\"PID\":512},...]\n```\n\n**Keep everything as strings** (`--raw`)\n\n```bash\necho -e \"id 007\\nport 5432\" | json_encode -k --raw\n{\"id\":\"007\",\"port\":\"5432\"}\n```\n\n**Newline-delimited JSON for log shippers** (`-l`)\n\n```bash\necho -e \"a\\nb\\nc\" | json_encode -l\n\"a\"\n\"b\"\n\"c\"\n```\n\n**Custom delimiter** (`-d`)\n\n```bash\necho -e \"a,b,c\\nd,e,f\" | json_encode -c -d ,\n[[\"a\",\"b\",\"c\"],[\"d\",\"e\",\"f\"]]\n```\n\n## Upgrading from 2.x\n\n3.0 renames flags for consistency (GNU-style short + long) and turns two former\nflags into defaults. Old flag → new flag:\n\n| 2.x | 3.0 |\n|-----|-----|\n| `-s SEP` | `-d, --delimiter SEP` |\n| `-sc` | `-c, --columns` |\n| `-cols A,B` | `-n, --names A,B` |\n| `-header` | `-H, --header` |\n| `-kv` | `-k, --kv` |\n| `-w` | *(now the default; use `-d` for a literal delimiter)* |\n| `-t` | *(type inference is now on; use `--raw` to disable)* |\n| `-nd` | `-l, --jsonl` |\n| `-stream` | `-F, --follow` |\n| `-o` (wrap) | `--wrap` |\n| *(n/a)* | `-o, --output FILE` now writes to a file |\n| `-v` / `-version` | `-V, --version` |\n\n## Advanced usage\n\n### Collect failed systemd units for an alert\n\n```bash\nsystemctl list-units --state=failed --no-legend \\\n  | awk '{print $1}' \\\n  | json_encode\n[\"nginx.service\",\"mysql.service\"]\n```\n\n### Processes as typed objects, no `tr -s` needed\n\nWhitespace splitting and a header row turn `ps` straight into self-describing,\ntyped records:\n\n```bash\nps -eo pid,comm,pcpu,rss | json_encode -H -l\n{\"COMMAND\":\"systemd\",\"PID\":1,\"%CPU\":0,\"RSS\":12344}\n{\"COMMAND\":\"sshd\",\"PID\":512,\"%CPU\":0.1,\"RSS\":4096}\n```\n\n`-l` emits one object per line — ready to pipe into Elasticsearch `_bulk`, Loki,\nVector or Fluent Bit.\n\n### `docker ps` straight to objects — no `jq` needed\n\n```bash\ndocker ps --format 'table {{.Names}}\\t{{.Image}}\\t{{.Status}}' \\\n  | json_encode --tsv -H\n[{\"IMAGE\":\"nginx:latest\",\"NAMES\":\"web\",\"STATUS\":\"Up 2 hours\"},\n {\"IMAGE\":\"redis:7\",\"NAMES\":\"cache\",\"STATUS\":\"Up 5 days\"}]\n```\n\n### Numeric thresholds without `tonumber`\n\nNumbers arrive typed, so `jq` comparisons just work:\n\n```bash\ndf -h --output=source,pcent | tail -n +2 | tr -d ' %' \\\n  | json_encode -k \\\n  | jq -c 'to_entries | map(select(.value \u003e 80)) | map(.key)'\n[\"/dev/sda1\",\"/dev/sdc1\"]\n```\n\n### Project columns without `cut`\n\n`-f` picks fields (with ranges), and pairs with `-n` to name them:\n\n```bash\n# user, uid and shell from /etc/passwd, as named objects\njson_encode -d : -f 1,3,7 -n user,uid,shell /etc/passwd\n[{\"shell\":\"/bin/bash\",\"uid\":0,\"user\":\"root\"},...]\n```\n\n### Parse a CSV report and query it\n\nFile arguments auto-detect `.csv`/`.tsv`, and quoted fields are honoured:\n\n```bash\njson_encode -H costs.csv \\\n  | jq '.[] | select(.service==\"EC2\") | .cost'\n42.50\n```\n\n### Map running containers to their image\n\n```bash\ndocker ps --format '{{.ID}}\\t{{.Image}}' | json_encode -k -d $'\\t'\n{\"a1b2c3d4\":\"nginx:latest\",\"b5c6d7e8\":\"redis:7\"}\n```\n\n### Export environment as a JSON object\n\n```bash\nenv | json_encode -k -d =\n{\"HOME\":\"/root\",\"PATH\":\"/usr/bin:/bin\",\"USER\":\"root\",...}\n```\n\n### Git log as structured records\n\n```bash\ngit log --pretty=format:\"%h|%an|%ad|%s\" -n 3 | json_encode -c -d \"|\" -n hash,author,date,subject\n[{\"author\":\"Alice\",\"date\":\"...\",\"hash\":\"a1b2c3d\",\"subject\":\"fix: handle timeout\"},...]\n```\n\n### Inventory files safely with `find -print0`\n\n`-0` reads NUL-delimited input, so paths with spaces or newlines survive intact:\n\n```bash\nfind /var/log -name '*.log' -print0 | json_encode -0\n[\"/var/log/sys log.1\",\"/var/log/nginx/access.log\",...]\n```\n\n### Stamp a snapshot with host and timestamp\n\n`--wrap` envelopes the output with `host` and a UTC `timestamp` — a self-contained\naudit record. `-o` writes it straight to a file:\n\n```bash\nrpm -qa | sort | json_encode --wrap -o /var/audit/packages.json\n# {\"data\":[\"acl-2.3.1\",\"bash-5.2.15\",...],\"host\":\"web01\",\"timestamp\":\"2026-06-05T08:00:00Z\"}\n```\n\n### Ship access.log to Loki\n\nLoki's push API expects `{\"streams\":[{\"stream\":{labels},\"values\":[[\"timestamp_ns\",\"line\"],...]}]}`.\n\n**Batch — send the last N lines on a schedule (e.g. from cron):**\n\n```bash\ntail -n 500 /var/log/nginx/access.log \\\n  | json_encode --raw \\\n  | jq -c --arg job nginx --arg host \"$(hostname)\" \\\n      '{streams:[{stream:{job:$job,host:$host},\n                  values:[.[] | [(now*1e9|tostring), .]]}]}' \\\n  | curl -s -X POST http://loki:3100/loki/api/v1/push \\\n        -H 'Content-Type: application/json' -d @-\n```\n\n**Structured — parse fields and attach them as Loki stream labels:**\n\nnginx default log format: `IP - - [date] \"METHOD path proto\" status bytes`\n\n```bash\ntail -n 500 /var/log/nginx/access.log \\\n  | awk '{print $1\"|\"$7\"|\"$9}' \\\n  | json_encode -c -d '|' --raw \\\n  | jq -c --arg host \"$(hostname)\" \\\n      '[.[] | {ip:.[0], path:.[1], status:.[2]}] |\n       {streams:[{stream:{job:\"nginx\",host:$host},\n                  values:[.[] | [(now*1e9|tostring),\n                                 (\"ip=\"+.ip+\" path=\"+.path+\" status=\"+.status)]]}]}' \\\n  | curl -s -X POST http://loki:3100/loki/api/v1/push \\\n        -H 'Content-Type: application/json' -d @-\n```\n\n**Tail in real time — ship each new line as it arrives:**\n\n`-F/--follow` emits one JSON value per line the moment it appears (no `while read`\nloop, no waiting for EOF):\n\n```bash\ntail -f /var/log/nginx/access.log \\\n  | json_encode -F -l --raw \\\n  | while IFS= read -r line; do\n      printf '%s' \"$line\" \\\n        | jq -c --arg host \"$(hostname)\" \\\n            '{streams:[{stream:{job:\"nginx\",host:$host},\n                        values:[[(now*1e9|tostring), .]]}]}' \\\n        | curl -s -X POST http://loki:3100/loki/api/v1/push \\\n              -H 'Content-Type: application/json' -d @-\n    done\n```\n\n## Development\n\n```bash\nmake build            # compile → ./json_encode\nmake test             # go test -race ./...\nmake vet              # go vet ./...\nmake functional-test  # build + shell-level integration tests (needs jq)\nmake demo             # regenerate the README GIF (needs vhs + gifsicle)\nmake snapshot         # local GoReleaser build, no publish\nmake clean            # remove build artifacts\n```\n\nPure standard library, no runtime dependencies.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffedir%2Fjson_encode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffedir%2Fjson_encode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffedir%2Fjson_encode/lists"}