1% JO(1) User Manuals
2
3# NAME
4
5jo - JSON output from a shell
6
7# SYNOPSIS
8
9jo [-p] [-a] [-B] [-e] [-v] [-V] [-d keydelim] [--] [ [-s|-n|-b] word ...]
10
11# DESCRIPTION
12
13*jo* creates a JSON string on _stdout_ from _word_s given it as arguments or read from _stdin_. Without
14option `-a` it generates an object whereby each _word_ is a `key=value` (or `key@value`)
15pair with _key_ being the JSON object element and _value_ its value. *jo* attempts to
16guess the type of _value_ in order to create number (using _strtod(3)_), string, or null values in JSON.
17
18*jo* normally treats _key_ as a literal string value. If the `-d` option is specified, _key_ will be
19interpreted as an _object path_, whose individual components are separated by the first character of _keydelim_.
20
21*jo* normally treats _value_ as a literal string value, unless it begins with one of the following characters:
22
23value action
24----- ------
25@file substitute the contents of _file_ as-is
26%file substitute the contents of _file_ in base64-encoded form
27:file interpret the contents of _file_ as JSON, and substitute the result
28
29Escape the special character with a backslash to prevent this interpretation.
30
31*jo* treats `key@value` specifically as boolean JSON elements: if the value begins with `T`, `t`,
32or the numeric value is greater than zero, the result is `true`, else `false`. A missing or
33empty value behind the colon results in a `null` JSON element.
34
35*jo* creates an array instead of an object when `-a` is specified.
36
37When the `:=` operator is used in a _word_, the name to the right of `:=` is a file containing JSON which is parsed and assigned to the key left of the operator. The file may be specified as `-` to read from _jo_'s standard input.
38
39
40# TYPE COERCION
41
42*jo*'s type guesses can be overridden on a per-word basis by prefixing _word_ with `-s` for _string_,
43`-n` for _number_, or `-b` for _boolean_. The list of _word_s *must* be prefixed with `--`, to indicate
44to *jo* that there are no more global options.
45
46Type coercion works as follows:
47
48word         -s               -n           -b        default
49------------ ---------------- ------------ --------- ----------------
50a=           "a":""           "a":0        "a":false "a":null
51a=string     "a":"string"     "a":6        "a":true  "a":"string"
52a=\"quoted\" "a":"\"quoted\"" "a":8        "a":true  "a":"\"quoted\""
53a=12345      "a":"12345"      "a":12345    "a":true  "a":12345
54a=true       "a":"true"       "a":1        "a":true  "a":true
55a=false      "a":"false"      "a":0        "a":false "a":false
56a=null       "a":""           "a":0        "a":false "a":null
57
58Coercing a non-number string to number outputs the _length_ of the string.
59
60Coercing a non-boolean string to boolean outputs `false` if the string is empty, `true` otherwise.
61
62Type coercion only applies to `key=value` words, and individual words in a `-a` array.
63Coercing other words has no effect.
64
65# EXAMPLES
66
67Create an object. Note how the incorrectly-formatted float value becomes a string:
68
69	$ jo tst=1457081292 lat=12.3456 cc=FR badfloat=3.14159.26 name="JP Mens" nada= coffee@T
70	{"tst":1457081292,"lat":12.3456,"cc":"FR","badfloat":"3.14159.26","name":"JP Mens","nada":null,"coffee":true}
71
72Pretty-print an array with a list of files in the current directory:
73
74	$ jo -p -a *
75	[
76	 "Makefile",
77	 "README.md",
78	 "jo.1",
79	 "jo.c",
80	 "jo.pandoc",
81	 "json.c",
82	 "json.h"
83	]
84
85Create objects within objects; this works because if the first character of value is an open brace or a bracket we attempt to decode the remainder as JSON. Beware spaces in strings ...
86
87	$ jo -p name=JP object=$(jo fruit=Orange hungry@0 point=$(jo x=10 y=20 list=$(jo -a 1 2 3 4 5)) number=17) sunday@0
88	{
89	 "name": "JP",
90	 "object": {
91	  "fruit": "Orange",
92	  "hungry": false,
93	  "point": {
94	   "x": 10,
95	   "y": 20,
96	   "list": [
97	    1,
98	    2,
99	    3,
100	    4,
101	    5
102	   ]
103	  },
104	  "number": 17
105	 },
106	 "sunday": false
107	}
108
109Booleans as strings or as boolean (pay particular attention to _switch_; the `-B` option disables the default detection of the "`true`", "`false`", and "`null`" strings):
110
111	$ jo switch=true morning@0
112	{"switch":true,"morning":false}
113
114	$ jo -B switch=true morning@0
115	{"switch":"true","morning":false}
116
117Elements (objects and arrays) can be nested. The following example nests an array called _point_ and an object named _geo_:
118
119	$ jo -p name=Jane point[]=1 point[]=2 geo[lat]=10 geo[lon]=20
120	{
121	   "name": "Jane",
122	   "point": [
123	      1,
124	      2
125	   ],
126	   "geo": {
127	      "lat": 10,
128	      "lon": 20
129	   }
130	}
131
132The same example, using object paths:
133
134	$ jo -p -d. name=Jane point[]=1 point[]=2 geo.lat=10 geo.lon=20
135	{
136	   "name": "Jane",
137	   "point": [
138	      1,
139	      2
140	   ],
141	   "geo": {
142	      "lat": 10,
143	      "lon": 20
144	   }
145	}
146
147Without `-d`, a different object is generated:
148
149	$ jo -p name=Jane point[]=1 point[]=2 geo.lat=10 geo.lon=20
150	{
151	   "name": "Jane",
152	   "point": [
153	      1,
154	      2
155	   ],
156	   "geo.lat": 10,
157	   "geo.lon": 20
158	}
159
160Create empty objects or arrays, intentionally or potentially:
161
162	$ jo < /dev/null
163	{}
164
165	$ MY_ARRAY=(a=1 b=2)
166	$ jo -a "${MY_ARRAY[@]}" < /dev/null
167	["a=1","b=2"]
168
169
170Type coercion:
171
172	$ jo -p -- -s a=true b=true -s c=123 d=123 -b e="1" -b f="true" -n g="This is a test" -b h="This is a test"
173	{
174	   "a": "true",
175	   "b": true,
176	   "c": "123",
177	   "d": 123,
178	   "e": true,
179	   "f": true,
180	   "g": 14,
181	   "h": true
182	}
183
184	$ jo -a -- -s 123 -n "This is a test" -b C_Rocks 456
185	["123",14,true,456]
186
187Read element values from files: a value which starts with `@` is read in plain whereas if it begins with a `%` it will be base64-encoded and if it starts with `:` the contents are interpreted as JSON:
188
189	$ jo program=jo authors=@AUTHORS
190	{"program":"jo","authors":"Jan-Piet Mens <jpmens@gmail.com>"}
191
192	$ jo filename=AUTHORS content=%AUTHORS
193	{"filename":"AUTHORS","content":"SmFuLVBpZXQgTWVucyA8anBtZW5zQGdtYWlsLmNvbT4K"}
194
195	$ jo nested=:nested.json
196	{"nested":{"field1":123,"field2":"abc"}}
197
198These characters can be escaped to avoid interpretation:
199
200	$ jo name="JP Mens" twitter='\@jpmens'
201	{"name":"JP Mens","twitter":"@jpmens"}
202
203	$ jo char=" " URIescape=\\%20
204	{"char":" ","URIescape":"%20"}
205
206	$ jo action="split window" vimcmd="\:split"
207	{"action":"split window","vimcmd":":split"}
208
209Read element values from a file in order to overcome ARG_MAX limits during object assignment:
210
211	$ ls | jo -a > child.json
212	$ jo files:=child.json
213	{"files":["AUTHORS","COPYING","ChangeLog" ....
214
215	$ ls *.c | jo -a > source.json; ls *.h | jo -a > headers.json
216	$ jo -a :source.json :headers.json
217	[["base64.c","jo.c","json.c"],["base64.h","json.h"]]
218
219# OPTIONS
220
221*jo* understands the following global options.
222
223-a
224:   Interpret the list of _words_ as array values and produce an array instead of
225    an object.
226
227-B
228:   By default *jo* interprets the strings "`true`" and "`false`" as boolean elements
229    `true` and `false` respectively, and "`null`" as `null`. Disable with this option.
230
231-e
232:   Ignore empty stdin (i.e. don't produce a diagnostic error when *stdin*
233    is empty)
234
235-p
236:   Pretty-print the JSON string on output instead of the terse one-line output it
237    prints by default.
238
239-v
240:   Show version and exit.
241
242-V
243:   Show version as a JSON object and exit.
244
245# BUGS
246
247Probably.
248
249If a value given to *jo* expands to empty in the shell, then *jo* produces a `null` in object mode, and might appear to hang in array mode; it is not hanging, rather it's reading _stdin_. This is not a bug.
250
251Numeric values are converted to numbers which can produce undesired results. If you quote a numeric value, *jo* will make it a string. Compare the following:
252
253	$ jo a=1.0
254	{"a":1}
255	$ jo a=\"1.0\"
256	{"a":"1.0"}
257
258Omitting a closing bracket on a nested element causes a diagnostic message to print, but the output contains garbage anyway. This was designed thusly.
259
260# RETURN CODES
261
262*jo* exits with a code 0 on success and non-zero on failure after indicating what
263caused the failure.
264
265# AVAILABILITY
266
267<http://github.com/jpmens/jo>
268
269# CREDITS
270
271* This program uses `json.[ch]`, by Joseph A. Adams.
272
273# SEE ALSO
274
275* <https://stedolan.github.io/jq/>
276* <https://github.com/micha/jsawk>
277* <https://github.com/jtopjian/jsed>
278* strtod(3)
279
280# AUTHOR
281
282Jan-Piet Mens <http://jpmens.net>
283
284