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"


Enter jo:

$ jo 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

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

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": [

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!


Toolbox and JSON :: 05 Mar 2016 :: e-mail