Shell脚本中解析json

由于工作需要,需要在Shell脚本中解析json文件。

安装软件

这里需要使用开源jq命令,首先从官方下载最新版jq

https://stedolan.github.io/jq/download/ 例如https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64

下载之后将jq-linux64重命名为jq

$ mv jq-linux64 jq

然后执行./jq即可查看帮助

最简单的示例

$  echo '{"foo": 0,"bar":1}' | ./jq .
{
  "foo": 0,
  "bar": 1
}

注意jq后面的点号,其表示格式化输出json串。还可以直接处理已有的文件,如下

$cat jsonData.josn 
{"productId":"2723","click":60,"view":300,"deal":2,"day":"20130919"}
{"productId":"2728","click":130,"view":800,"deal":10,"day":"20130919"}
{"productId":"3609","click":50,"view":400,"deal":3,"day":"20130919"}

$./jq -r . jsonData.josn 
{
  "productId": "2723",
  "click": 60,
  "view": 300,
  "deal": 2,
  "day": "20130919"
}
{
  "productId": "2728",
  "click": 130,
  "view": 800,
  "deal": 10,
  "day": "20130919"
}

...

示例

提取json字段

例如我们需要提取所有的productId及其click,那么我们就可以这样:

./jq -r '.productId +","+(.click|tostring)' jsonData.josn 
2723,60
2728,130
3609,50

需要注意的是,由于click的值是数值,其不能直接和字符串进行拼接,所以我们对其调用了tostring的方法,语法为(.click|tostring);

然后我们通过+来将两个字段以及逗号进行了拼接;

另外注意每个属性名前的点号(.productId),点号表示根节点

访问数组

考虑如下json

{
"tasks": {
    "task": [
            {       
                "id": "task_1550858682031_448878_m_000869",
                "startTime": 1551150749829,
                "finishTime": 1551150766484
            },
            {
                "id": "task_1550858682031_448878_m_001389",
                "startTime": 1551150904151,
                "finishTime": 1551150920778
            }
            ]
        }
}

task是一个数组,怎么将所有task的id及startTime,finishTime以csv的格式输出呢,如下:

第一步,遍历数组

./jq -r '.tasks.task[]' task.json 
{
  "id": "task_1550858682031_448878_m_000869",
  "startTime": 1551150749829,
  "finishTime": 1551150766484
}
{
  "id": "task_1550858682031_448878_m_001389",
  "startTime": 1551150904151,
  "finishTime": 1551150920778
}

可以看到,数组是通过[]来访问的,[]表示遍历整个数组,如果你只想访问数组中的第2个元素(下标从0开始),你可以使用[1];如果想要访问第3个到第5个元素,可以使用[2:4]

第二步,访问每个元素的属性

./jq -r '.tasks.task[].id,.tasks.task[].startTime,.tasks.task[].finishTime' task.json
task_1550858682031_448878_m_000869
task_1550858682031_448878_m_001389
1551150749829
1551150904151
1551150766484
1551150920778

怎么没有按列输出,而是按行输出了呢?这是因为如果表达式被逗号分隔,则表示对进同一输入应用两次表达式,产生多行输出。那如果我想在一行中输出应该怎么办呢?当然是只编写一个表达式,怎么只编写一个表达式呢?

答案是使用管道符|,如下

./jq -r '.tasks.task[] | .id +","+(.startTime|tostring)+","+(.finishTime|tostring)' task.json
task_1550858682031_448878_m_000869,1551150749829,1551150766484
task_1550858682031_448878_m_001389,1551150904151,1551150920778

定义数组

除了上面的使用+来进行字符串拼接,我们还可以使用[]来定义数组,然后直接输出数组,更简洁

./jq -r '[.productId,.click]' jsonData.josn
[
  "2723",
  60
]
[
  "2728",
  130
]
[
  "3609",
  50
]

还可以调用数组的join方法,来将数组转换成拼接字符串,如下

./jq -r '([.productId,.click])|join(",")' jsonData.josn
2723,60
2728,130
3609,50

输出格式

除了使用前面字符串拼接的方式来输出csv格式之外,我们还可以使用预置的格式指令,例如@csv

./jq -r '.tasks.task[] | [.id,.startTime,.finishTime] | @csv' task.json
"task_1550858682031_448878_m_000869",1551150749829,1551150766484
"task_1550858682031_448878_m_001389",1551150904151,1551150920778

因为@csv的输入必须是数组,所以我们使用[.id,.startTime,.finishTime]来构造了数组

更多其它使用方法请参考如下链接

官方文档:https://stedolan.github.io/jq/manual

表达式在线测试器:https://jqplay.org/

教程:https://github.com/stedolan/jq/wiki/Cookbook

(0)

相关推荐