OpenWrt jshn.sh 詳細說明

以下介紹OpenWrt 中的jshn.sh。

1. jshn是一個生成或分析JSON 格式的小工具,其程試碼在libubox 的jshn.c。jshn.sh 則提供各個操作JSON 的API,可以在自己實作的script 中,透過其API 生成或分析JSON 資料。jshn.sh可以在OpenWrt 系統中,/usr/share/libubox 下找到。

2. 介紹jshn.sh 前,先簡單介紹JSON。

JSON 的資料格試為:

key:value

其中key必須在雙引號””中,value可以是

  • 數字 (int double )
  • 字串 (string)
  • 布林值 (boolean)
  • 物件 (object)
  • 陣列 (array)
  • null

數字

{"number1":100,"number2":1.23}

字串

{"name":"Tom"}

布林值

{"up":false,"down":true}

物件必須在大括號{}中。

{"Influencer":{"name":"Tom","age":"42","city","New York"}}

陣列必須在中括號[]中,陣列值必須是字串、數字、物件、陣列、布林值或 null 類型

{"dns-server":[
	"1.1.1.1",
	"8.8.8.8"
]}

在上面的例子中,為一個有二個字串的陣列。

{"ipv4-address":[
	{"address":"192.168.1.102","mask":24},
	{"address": "192.168.2.103","mask":24}
]}

在上面的例子中,為一個有二個物件的陣列。

3. jshn.sh提供以下API:

  • json_add_string
  • json_add_int
  • json_add_double
  • json_add_boolean
  • json_add_null
  • json_add_object、json_close_object
  • json_add_array、json_close_array
  • json_load、json_load_file
  • json_dump
  • json_select
  • json_get_type
  • json_get_keys
  • json_get_values
  • json_get_var
  • json_is_a
  • json_for_each_item

json_add_stringjson_add_intjson_add_doublejson_add_booleanjson_add_null :

#!/bin/sh
. /usr/share/libubox/jshn.sh

json_init
json_add_string "msg" "hello,world"
json_add_int "uptime" 100
json_add_double "angle" 36.1
json_add_boolean "up" false
json_add_null "device"
生成JSON為
{"msg":"hello.world","uptime":100,"angle":36.1,"up":false,"device":null}

json_add_objectjson_close_object :

#!/bin/sh
. /usr/share/libubox/jshn.sh

json_init
json_add_object "test"
json_close_object
json_add_object "appliaction"
json_add_string "version" "0.0.1"
json_add_object "script"
json_add_string "start" "node ./bin/www"
json_close_object
json_close_object
生成JSON為
{"test":{},
"application":{"version":"0.0.1","script":{"start":"node ./bin/www"}}}

須注意add object 完成之後,必須close object。


json_add_arrayjson_close_array :

#!/bin/sh
. /usr/share/libubox/jshn.sh

json_init
json_add_array "test"
json_close_array
json_add_array "dns-server"
json_add_string "" "1.1.1.1" #在array中,增加第一個string值
json_add_string "" "8.8.8.8" #在array中,增加第二個string值
json_close_array
json_add_array "ipv4-address"
json_add_object "" #在array中,增加第一個object值
json_add_string "address" "192.168.1.100"
json_add_int "mask" 24
json_close_object
json_add_object "" #在array中,增加第二個object值
json_add_string "address" "192.168.2.100"
json_add_int "mask" 24
json_close_object
json_close_array
生成JSON為
{"test":[],
"dsn-server":["1.1.1.1","8.8.8.8"],
"ipv4-address":[
{"address":"192.168.1.100","mask":24},
{"address":"192.168.2.100","mask":24}
]}

須注意add array 完成之後,必須close array。


json_loadjson_load_filejson_dump :

#!/bin/sh
. /usr/share/libubox/jshn.sh

json_data="{\"msg\":\"hello,world\"}"
json_load $json_data
dump_json_data=$(json_dump)
echo $dump_json_data
執行結果為
{"msg":"hello,world"}

若有一檔案json_file,位於tmp,其內容如下:

{"msg":"hello,world"}
#!/bin/sh
. /usr/share/libubox/jshn.sh

json_load_file "/tmp/json_file"
dump_json_data=$(json_dump)
echo $dump_json_data
執行結果為
{"msg":"hello,world"}

json_load 可以讀取一JSON 格式字串,json_load_file 可以讀取一個內容為JSON 格式的文件。讀取之後,可以透過json_dump 將JSON 資料取出。


json_select :

是用來選擇JSON 中的objectarray。以下面JSON 為範列:

{                                 #第一層
  "msg": "hello, world",          #      
  "up": false,                    # 
  "uptime": 100,                  #
  "interface": "eth0.2",          # 
  "angle": 36.1,                  #
  "device": null,                 #
  "application": {                        #第二層application
    "version": "0.0.1",                   #
    "script": {                                 #第三層script
      "start": "node ./bini/www"                #
    }                                           #第三層script結尾
  },                                      #第二層application結尾
  "dns-server": [                         #第二層dns-server
    "1.1.1.1",                            #
    "8.8.8.8"                             #
  ],                                      #第二層dns-server結尾
  "ipv4-address": [                       #第二層ipv4-address
    {                                           #第三層object1
      "address": "192.168.1.102",               # 
      "mask": 24                                # 
    },                                          #第三層object1結尾
    {                                           #第三層object2
      "address": "192.168.2.103",               #
      "mask": 24                                #
    }                                           #第三層object2結尾
  ]                                        #第二層ipv4-address結尾
}                                  #第一層結尾
以上面JSON 範例,若要選擇第二層application object,則執行
json_select "application"
要跳回第一層,則再執行
json_select ..
若要選擇第三層script object,則需執行
json_select "application"
json_selct "script"
要跳回第一層,則需執行
json_select ..
json_select ..

將JSON 中的object 或array,類推為目錄(文件夾);JSON 中的key 值,類推為檔案。因此,可以將JSON 資料類推如下:

所以json_select 就如指令cd一樣。返回上一層就使用

json_select ..

若要到指定的object 或array (到指定的目錄),就使用

json_select "object 或array 名稱"

json_get_type :

是用來得到值的類型。以下面JSON 為範列,/tmp/json_file 如下:

{  
  "msg": "hello, world", 
  "up": false,                     
  "uptime": 100,
  "interface": "eth0.2", 
  "angle": 36.1,
  "device": null,
	"application": {
    "version": "0.0.1",
    "script": {
      "start": "node ./bini/www"
    }
  },
  "dns-server": [
    "1.1.1.1",
    "8.8.8.8"
  ],
}
#!/bin/sh
. /usr/share/libubox/jshn.sh

json_load_file "/tmp/json_file"
json_get_type type "msg"
echo $type
json_get_type type "up"
echo $type
json_get_type type "uptime"
echo $type
json_get_type type "interface"
echo $type
json_get_type type "angle"
echo $type
json_get_type type "device"
echo $type
json_get_type type "application"
echo $type
json_get_type type "dns-server"
echo $type
執行結果為
string
boolean
int
string
double
null
object
array

json_get_keys :

是用來得到目前object 下的所有key 值。以下面JSON 為範列,/tmp/json_file 如下:

{  
  "msg": "hello, world", 
  "up": false,                     
  "uptime": 100,
  "interface": "eth0.2", 
  "angle": 36.1,
  "device": null,
	"application": {
    "version": "0.0.1",
    "script": {
      "start": "node ./bini/www"
    }
  },
  "dns-server": [
    "1.1.1.1",
    "8.8.8.8"
  ],
}
#!/bin/sh
. /usr/share/libubox/jshn.sh

json_load_file "/tmp/json_file"
json_get_keys keys
echo $keys
json_select "application"  #object
json_get_keys keys
echo $keys
json_select ..
json_select "dns-server"   #array
json_get_keys keys
echo $keys
執行結果為
msg up uptime interface angle application dns-server
version script
1 2

json_get_values :

是用來得到目前object 下的所有value 值。以下面JSON 為範列,/tmp/json_file 如下:

{  
  "msg": "hello, world", 
  "up": false,                     
  "uptime": 100,
  "interface": "eth0.2", 
  "angle": 36.1,
}
#!/bin/sh
. /usr/share/libubox/jshn.sh

json_load_file "/tmp/json_file"
json_get_values values
echo $values
執行結果為
hello,world 0 100 eth0.2 36.100000

json_get_var :

是用來得到指定key 時,相對應的value 值。以下面JSON 為範列,/tmp/json_file 如下:

{  
  "msg": "hello, world", 
  "up": false,                     
  "uptime": 100,
  "interface": "eth0.2", 
  "angle": 36.1,
  "device": null,
	"application": {
    "version": "0.0.1",
    "script": {
      "start": "node ./bini/www"
    }
  },
  "dns-server": [
    "1.1.1.1",
    "8.8.8.8"
  ],
}
#!/bin/sh
. /usr/share/libubox/jshn.sh

json_load_file "/tmp/json_file"
json_get_var tmp "msg"
echo $tmp
json_select "application"   #指定到第二層application
json_get_var tmp "version"
echo $tmp
json_select "script"        #指定到第三層script
json_get_var tmp "start"
echo $tmp
json_select ..              #回到第二層application
json_select ..              #回到第一層
json_select "dns-server"
json_get_var tmp 1          #讀取array的第一個key,所對應的value值
echo $tmp
json_get_var tmp 2          #讀取array的第二個key,所對應的value值
echo $tmp
執行結果為
hello,world
0.0.1
node ./bin/www
1.1.1.1
8.8.8.8

json_is_a :

用於判斷value 值的類型。以下面JSON 為範列,/tmp/json_file 如下:

{  
  "msg": "hello, world", 
  "up": false,                     
  "uptime": 100,
  "interface": "eth0.2", 
  "angle": 36.1,
  "device": null,
	"application": {
    "version": "0.0.1",
    "script": {
      "start": "node ./bini/www"
    }
  },
  "dns-server": [
    "1.1.1.1",
    "8.8.8.8"
  ],
}
#!/bin/sh
. /usr/share/libubox/jshn.sh

json_load_file "/tmp/json_file"
json_select "dns-server"
idx=1
while json_is_a $idx string
do
	json_get_var tmp $idx
	echo $tmp
	idx=$((idx+1))
done
執行結果為
1.1.1.1
8.8.8.8

json_for_each_item :

以下面JSON 為範列,/tmp/json_file 如下:

{  
  "msg": "hello, world", 
  "up": false,                     
  "uptime": 100,
  "interface": "eth0.2", 
  "angle": 36.1,
  "device": null,
	"application": {
    "version": "0.0.1",
    "script": {
      "start": "node ./bini/www"
    }
  },
  "dns-server": [
    "1.1.1.1",
    "8.8.8.8"
  ],
	"ipv4-address": [
    {
      "address": "192.168.1.102",
      "mask": 24
    },
    {
      "address": "192.168.2.103",
      "mask": 24
    }
  ]
}
#!/bin/sh
. /usr/share/libubox/jshn.sh

json_load_file "/tmp/json_file"

myprint1() {
	echo $1--$2
}

myprint2(){
	json_select $2
	json_get_var tmp "address"
	echo $tmp
	json_select ..
}

json_for_each_item myprint1 "dns-server"
json_for_ecth_item myprint2 "ipv4-address"
執行結果為
1.1.1.1--1
8.8.8.8--2
192.168.1.102
192.168.2.103

4. 範例:

{
  "msg": "hello, world",
  "up": false,
  "uptime": 100,
  "interface": "eth0.2",
  "angle": 36.1,
  "device": null,
  "application": {
    "version": "0.0.1",
    "script": {
      "start": "node ./bini/www"
    }
  },
  "dns-server": [
    "1.1.1.1",
    "8.8.8.8"
  ],
  "ipv4-address": [
    {
      "address": "192.168.1.102",
      "mask": 24
    },
    {
      "address": "192.168.2.103",
      "mask": 24
    }
  ]
}

根據上面JSON 資料,可以使用以下script 生成。

#!/bin/sh

. /usr/share/libubox/jshn.sh

json_init
json_add_string "msg" "hello, world"
json_add_boolean "up" false
json_add_int "uptime" 100
json_add_string "interface" "eth0.2"
json_add_double "angle" 36.1
json_add_null "device"
json_add_object "application"
json_add_string "version" "0.0.1"
json_add_object "script"
json_add_string "start" "node ./bini/www"
json_close_object
json_close_object
json_add_array "dns-server"
json_add_string "" "1.1.1.1"
json_add_string "" "8.8.8.8"
json_close_array
json_add_array "ipv4-address"
json_add_object ""
json_add_string "address" "192.168.1.102"
json_add_int "mask" 24
json_close_object
json_add_object ""
json_add_string "address" "192.168.2.103"
json_add_int "mask" 24
json_close_object
json_close_array

json=$(json_dump)
echo $json

執行結果如下:

檔案/tmp/json_data 如下:

使用以下script 驗證:

#!/bin/sh

. /usr/share/libubox/jshn.sh

json_load_file "/tmp/json_data"
json_get_var tmp "msg"
echo "msg="$tmp
json_get_var tmp "up"e
cho "up="$tmp
json_get_var tmp "uptime"
echo "uptime="$tmp
json_get_var tmp "interface"
echo "interface="$tmp
json_get_var tmp "angle"
echo "angle="$tmp
json_get_var tmp "device"
echo "device="$tmp
json_select "application"
json_get_var tmp "version"
echo "version="$tmp
json_select "script"
json_get_var tmp "start"
echo "start="$tmp
json_select ..
json_select ..

json_select "dns-server"
idx=1
while json_is_a $idx string
do        
	json_get_var tmp $idx        
	echo $idx"="$tmp        
	idx=$((idx+1))
done
json_select ..

json_select "ipv4-address"
idx=1
while json_is_a $idx object
do        
	json_select $idx        
	json_get_var tmp "address"        
	echo "address="$tmp        
	json_get_var tmp "mask"        
	echo "mask="$tmp        
	json_select ..        
	idx=$((idx+1))
done

其執行結果如下:

發佈留言