https://jpmens.net/2016/03/05/a-shell-command-to-create-json-jo/ * * * Atom * Search [ ] * Pages * Archives * @jpmens * About * Support Jan-Piet Mens A shell command to create JSON: jo I got tired of attempting to get shell scripts to produce valid JSON. You've likely seen something like this before: echo '{"name":"Jane"}' It gets merrier if an element contains an environment variable: open double, close single, add variable, open single, blergh. A here! script will do it as will a a printf(1), but neither much improve legibility, and if strings contain quotes, it becomes almost impossible to make a script produce JSON. printf '{"name": "%s"}\n' "Jane" Logo Enter jo: $ jo name=Jane {"name":"Jane"} The idea occurred to me late at night, and I don't know why this has taken so long to happen: $ jo time=$(date +%s) dir=$HOME {"time":1457195712,"dir":"/Users/jpm"} Bam! Jo tries to be clever about types and knows null, booleans, strings and numbers. It does arrays, and it pretty-prints on demand: $ jo -p -a spring summer winter [ "spring", "summer", "winter" ] Inspired by a comment on HN, I added another hack: if a key's value begins with an opening brace ({) or a bracket ([]) we attempt to decode JSON from it; this allows jo to add objects or arrays (use -a!) to itself. Watch: $ jo -p name=JP object=$(jo fruit=Orange point=$(jo x=10 y=20) number=17) sunday=false { "name": "JP", "object": { "fruit": "Orange", "point": { "x": 10, "y": 20 }, "number": 17 }, "sunday": false } jo also supports nested types natively: $ jo -p number=17 pass=true geo[lon]=88 geo[cc]=ES point[]=1 point[]=2 geo[lat]=123.45 { "number": 17, "pass": true, "geo": { "lon": 88, "cc": "ES", "lat": 123.45 }, "point": [ 1, 2 ] } Why did I do this? I need lots of JSON for testing OwnTracks, and this just looks better in scripts. $ jo _type=location \ cog=$((RANDOM % 360)) \ t=u \ lat=48.85833 \ lon=2.29513 \ acc=5 \ tid=JJ \ tst=$(date +%s) | mosquitto_pub -t owntracks/jjolie/test -l A suggestion by Andrew Bibby brought along the possibility of obtaining JSON element values from files, so I added @file to read a file (sans traling newline or carriage return) into a value as well as something which I use a lot, convert binary files to base64, using the %file syntax: $ jo _type=card name="Vanessa" face=%vanessa.png {"_type":"card","name":"Vanessa","face":"iVBORw0KGgoAAA ... QmCC"} And it has a man page. Go get it. Jo! Updates: * Caius Durling provided a Homebrew tap for jo, but jo is in Homebrew Formulae now, so brew install jo. * jo has a logo which it created itself; colors inspired by something Frederic Cambus said :-) * Shawn Webb added jo to HardenedBSD's ports. * I've converted jo to use autotools; releases will be published here. * Alessio Sergi has added jo to voidlinux; install with xbps-install -Su jo * I've built a Win32 binary which you can get from releases/. * Lance Chen has an ArchLinux port of jo. * Vincent Bernat has submitted jo to Debian. Toolbox and JSON :: 05 Mar 2016 :: e-mail