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" } }

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

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>
  • -w write to stdout
  • -o <file> write to file <file>
  • -p <prefix> set prefix
  • -n no newline
  • -i indent

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)"
#!/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"
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2020/01/11 23:20
  • by stokito