在前面兩篇文章中,咱們分別介紹了快速讀取 JSON 值的庫gjson
和快速設置 JSON 值的庫sjson
。今天咱們介紹它們的做者tidwall的一個基於gjson
和sjson
的很是實用的命令行工具jj
。它是使用 Go 編寫的快速讀取和設置 JSON 值的命令行程序。git
Mac 上能夠直接使用brew install tidwall/jj/jj
安裝。其餘系統能夠經過下載編譯好的可執行程序,下載地址爲https://github.com/tidwall/jj/releases。github
我選擇使用go get
安裝:golang
$ go get github.com/tidwall/jj/cmd/jj
上面命令執行完成以後,編譯生成的jj
程序會放在$GOPATH/bin
目錄中,我習慣把$GOPATH/bin
加入系統可執行目錄$PATH
中,故能夠直接使用。shell
簡單的讀取和設置(個人環境爲 Win10 + Git Bash):json
$ echo '{"name":{"first":"li","last":"dj"}}' | jj name.last dj $ echo '{"name":{"first":"li","last":"dj"}}' | jj -v dajun name.last {"name":{"first":"li","last":"dajun"}}
經過鍵路徑來指定讀取/設置的位置,上面第一個命令讀取字段name.last
,返回dj
。數組
-v
選項指定設置的值。第二個命令將字段name.last
設置爲dajun
,輸出設置以後的 JSON 串。鍵路徑在前兩篇文章中有詳細的介紹,不熟悉的能夠回去看一下。微信
實際上讀取和設置的語法和形式與咱們前面介紹gjson
和sjson
提到的基本同樣,只不過是在命令行上完成的而已。app
讀取不存在的字段,返回null
:工具
$ echo '{"name":{"first":"li","last":"dj"}}' | jj name.middle null
讀取一個對象類型的字段,返回該對象的 JSON 表示:性能
$ echo '{"name":{"first":"li","last":"dj"}}' | jj name {"first":"li","last":"dj"}
使用索引(從 0 開始)讀取數組的元素,非法的索引將返回空:
$ echo '{"fruits":["apple","orange","banana"]}' | jj fruits.1 orange $ echo '{"fruits":["apple","orange","banana"]}' | jj fruits.3
使用索引設置數組的元素,下面命令將數組fruits
的第二個元素設置爲pear
:
$ echo '{"fruits":["apple","orange","banana"]}' | jj -v pear fruits.1 {"fruits":["apple","pear","banana"]}
使用-1
或數組長度做爲索引,能夠在數組後添加一個元素。若是索引超過了數組長度,則會多必定數量的null
:
$ echo '{"fruits":["apple","orange","banana"]}' | jj -v strawberry fruits.-1 {"fruits":["apple","orange","banana","strawberry"]} $ echo '{"fruits":["apple","orange","banana"]}' | jj -v grape fruits.3 {"fruits":["apple","orange","banana","grape"]} $ echo '{"fruits":["apple","orange","banana"]}' | jj -v watermelon fruits.5 {"fruits":["apple","orange","banana",null,null,"watermelon"]}
使用選項-D
刪除指定鍵路徑上的元素,若是對應元素不存在,則無效果:
$ echo '{"name":"dj","age":18}' | jj -D age {"name":"dj"} $ echo '{"fruits":["apple","orange","banana"]}' | jj -D fruits.2 {"fruits":["apple","orange"]} $ echo '{"fruits":["apple","orange","banana"]}' | jj -D fruits.5 {"fruits":["apple","orange","banana"]}
第 1 個命令刪除字段age
;第 2 個命令刪除數組fruits
的第 2 個元素;第 3 個命令刪除數組fruits
的第 5 個元素,因爲數組長度只有 3,故無效果。
jj
支持從文件中讀取 JSON 串和將結果寫到文件中。使用選項-i
指定輸入文件,選項-o
指定輸出文件。下面將從文件fruits.txt
中讀取 JSON 串,取數組的第 2 個元素,寫到out.txt
中:
$ jj -i fruits.txt -o out.txt fruits.1
fruits.txt
的文件內容以下:
{"fruits":["apple","orange","banana"]}
執行命令,輸出文件的內容爲:
orange
jj
支持將輸出的 JSON 串進行必定的格式化。選項-u
移除全部的空白符,節省存儲空間。選項-p
美化格式,便於閱讀。
$ echo '{"name":{"first": "li", "last":"dj"}, "age":18}' | jj -u name {"first":"li","last":"dj"} $ echo '{"name":{"first": "li", "last":"dj"}, "age":18}' | jj -p name { "first": "li", "last": "dj" }
與另外一個 JSON 的命令行工具jq
相比,jj
是其性能的 10 倍以上。由於jj
不會驗證 JSON 串的有效性,而且它只關心鍵路徑指定的值,一旦該值處理完成就中止。這裏有性能對比:https://github.com/tidwall/jj#performance
jj
一個很方便的用途在於日誌處理,當前不少日誌庫都支持 JSON 的格式,例如前面咱們介紹的logrus
。咱們可使用jj
在這些日誌中找到相應的信息。咱們先用logrus
生成 20 條玩家登錄和下線的日誌:
package main import "github.com/sirupsen/logrus" func main() { logrus.SetFormatter(&logrus.JSONFormatter{}) for i := 1; i <= 10; i++ { logrus.WithFields(logrus.Fields{ "userid": i, }).Info("login") logrus.WithFields(logrus.Fields{ "userid": i, }).Info("logoff") } }
生成日誌存儲在log.txt
文件中:
{"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":1} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":1} {"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":2} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":2} {"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":3} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":3} {"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":4} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":4} {"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":5} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":5} {"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":6} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":6} {"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":7} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":7} {"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":8} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":8} {"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":9} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":9} {"level":"info","msg":"login","time":"2020-03-26T23:36:04+08:00","userid":10} {"level":"info","msg":"logoff","time":"2020-03-26T23:36:04+08:00","userid":10}
因爲每一行都是一個單獨的 JSON 串,咱們可使用jj
支持的 JSON 行特性,使用..
路徑標識這些行。..
使得jj
將這些行當作數組的元素。咱們能夠讀取這些數組元素。
獲取數組長度,返回 20:
$ jj -i log.txt ..# 20
只讀取每一行中的userid
信息:
$ jj -i log.txt ..#.userid [1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10]
只讀取每一行中的msg
信息:
$ jj -i log.txt ..#.msg ["login","logoff","login","logoff","login","logoff","login","logoff","login","logoff","login","logoff","login","logoff","login","logoff","login","logoff","login","logoff"]
更復雜一點的,若是咱們要查看全部userid=1
的日誌:
$ jj -i log.txt ..#\(userid=1\)# -p [ { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 1 }, { "level": "info", "msg": "logoff", "time": "2020-03-26T23:36:04+08:00", "userid": 1 } ]
上面的命令注意兩點,(
和)
是 shell 中的特殊字符,須要\
轉義。命令中咱們使用-p
選項使結果更易讀。
若是咱們只須要查找第一條符合條件的日誌,則能夠去掉最右側的#
:
$ jj -i log.txt ..#\(userid=1\) -p { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 1 }
若是要查看全部的登陸信息:
$ jj -i log.txt ..#\(msg="login"\)# -p [ { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 1 }, { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 2 }, { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 3 }, { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 4 }, { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 5 }, { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 6 }, { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 7 }, { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 8 }, { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 9 }, { "level": "info", "msg": "login", "time": "2020-03-26T23:36:04+08:00", "userid": 10 } ]
jj
是一個很是使用的 JSON 命令行工具,性能超讚。執行jj -h
去看看其餘選項吧。
你們若是發現好玩、好用的 Go 語言庫,歡迎到 Go 每日一庫 GitHub 上提交 issue😄
歡迎關注個人微信公衆號【GoUpUp】,共同窗習,一塊兒進步~