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