This is an old revision of the document!
jshn: a JSON parsing and generation library in for shell scripts
jshn (JSON SHell Notation), a small utility and shell library for parsing and generating JSON data.
Shell scripts (ash, bash, zsh) doesn't have built-in functions to work with JSON or other hierarchical structures so OpenWrt provides a shell library /usr/share/libubox/jshn.sh from libubox package.
You need to include it into your scripts and then you can call it's functions:
#!/bin/sh # source jshn shell library . /usr/share/libubox/jshn.sh # generating json data json_init json_add_string "msg" "Hello, world!" json_add_object "test" json_add_int "testdata" "1" json_close_object MSG=`json_dump` # MSG now contains: { "msg": "Hello, world!", "test": { "testdata": 1 } } # parsing json data json_load "$MSG" json_select test json_get_var var1 testdata json_select .. json_get_var var2 msg echo "msg: $var2 - testdata: $var1"
Another example:
#!/bin/sh # source jshn shell library . /usr/share/libubox/jshn.sh # initialize JSON output structure json_init # add a boolean field json_add_boolean foo 0 # add an integer field json_add_int code 123 # add a string, take care of escaping json_add_string result "Some complex string\n with newlines\n and even command output: $(date)" # add an array with three integers json_add_array alist json_add_int "" 1 json_add_int "" 2 json_add_int "" 3 json_close_array # add an object (dictionary) json_add_object adict json_add_string foo bar json_add_string bar baz json_close_object # build JSON object and print to stdout json_dump # will output something like this: # { "foo": false, "code": 123, "result": "Some complex string\\n with newlines\\n and even command output: Fri Jul 13 07:11:39 CEST 2018", "alist": [ 1, 2, 3 ], "adict": { "foo": "bar", "bar": "baz" } }
More complicated examples
Given the file:
- /data1.json
{ "status": 200, "msg": "ok", "result": { "number": "99", "mac": "d85d4c9c2f1a", "last_seen": 1363777473407 } }
Script to parse it:
#!/bin/sh . /usr/share/libubox/jshn.sh json_init json_load_file /data2.txt ## Load JSON from file ## json_get_var <local_var> <json_var> json_get_var status status ## Get Value of status inside JSON string (i.e. MSG) into local "status" variable json_get_var msg msg json_select result ## Select "result" object of JSON string (i.e. MSG) json_get_var number number json_get_var mac mac json_get_var last_seen last_seen
Given the file:
- /data2.json
{ "ip_addrs": { "lan": ["192.168.0.100","192.168.0.101","192.168.0.200"], "wan": ["10.11.12.22","10.11.12.23", "10.11.12.25"] } }
Script to parse it:
#!/bin/sh . /usr/share/libubox/jshn.sh json_init json_load_file /data2.json json_select "ip_addrs" if json_get_type Type lan && [ "$Type" == array ] then json_select lan local idx="1" while json_get_type Type "$idx" && [ "$Type" == string ] ## iterate over data inside "lan" object do json_get_var ip_addr $idx echo "$ip_addr" $((idx++)) 2> /dev/null done fi
jshn utility
Internally the /usr/share/libubox/jshn.sh is just a wrapper for /usr/bin/jshn utility.
You can use it directly:
root@OpenWrt:/# jshn Usage: jshn [-n] [-i] -r <message>|-R <file>|-o <file>|-p <prefix>|-w root@OpenWrt:/# jshn -i -R /etc/board.json json_init; json_add_object 'model'; json_add_string 'id' 'innotek-gmbh-virtualbox'; json_add_string 'name' 'innotek GmbH VirtualBox'; json_close_object; json_add_object 'network'; json_add_object 'lan'; json_add_string 'ifname' 'eth0'; json_add_string 'protocol' 'static'; json_close_object; json_add_object 'wan'; json_add_string 'ifname' 'eth1'; json_add_string 'protocol' 'dhcp'; json_close_object; json_close_object;
Options:
-r <message>parse from string<message>-R <file>parse from file<file>-wwrite to stdout-o <file>write to file<file>-p <prefix>set prefix-nno newline-iindent
Other examples
Get bridge status
OpenWrt have a command devstatus to check network device status:
root@OpenWrt:~# devstatus br-lan
{
"external": false,
"present": true,
"type": "bridge",
"up": true,
"carrier": true,
"bridge-members": [
"eth0.1",
"wlan0"
],
"mtu": 1500,
"mtu6": 1500,
"macaddr": "84:16:f9:9b:e0:7a",
"txqueuelen": 1000,
"ipv6": true,
"promisc": false,
"rpfilter": 0,
"acceptlocal": false,
"igmpversion": 0,
"mldversion": 0,
"neigh4reachabletime": 30000,
"neigh6reachabletime": 30000,
"neigh4gcstaletime": 60,
"neigh6gcstaletime": 60,
"neigh4locktime": 100,
"dadtransmits": 1,
"multicast": true,
"sendredirects": true,
"statistics": {
"collisions": 0,
"rx_frame_errors": 0,
"tx_compressed": 0,
"multicast": 0,
"rx_length_errors": 0,
"tx_dropped": 0,
"rx_bytes": 10609108786,
"rx_missed_errors": 0,
"tx_errors": 0,
"rx_compressed": 0,
"rx_over_errors": 0,
"tx_fifo_errors": 0,
"rx_crc_errors": 0,
"rx_packets": 39594607,
"tx_heartbeat_errors": 0,
"rx_dropped": 0,
"tx_aborted_errors": 0,
"tx_packets": 91154927,
"rx_errors": 0,
"tx_bytes": 121051584071,
"tx_window_errors": 0,
"rx_fifo_errors": 0,
"tx_carrier_errors": 0
}
}
And you can check it's sources which internally uses the jshn:
cat /sbin/devstatus
#!/bin/sh
. /usr/share/libubox/jshn.sh
DEVICE="$1"
[ -n "$DEVICE" ] || {
echo "Usage: $0 <device>"
exit 1
}
json_init
json_add_string name "$DEVICE"
ubus call network.device status "$(json_dump)"
Check if Link is up using devstatus and jshn
#!/bin/sh . /usr/share/libubox/jshn.sh WANDEV="$(uci get network.wan.ifname)" json_load "$(devstatus $WANDEV)" json_get_var var1 speed json_get_var var2 link echo "Speed: $var1" echo "Link: $var2"