文章目录

  • 1. JSON数据格式详解
  • 1.1 两种结构
  • 1.2 使用范例
  • 2. jq
  • 2.1 安装
  • 2.2 jq 基础使用
  • 2.2.1 基本语法
  • 2.2.2 基础使用
  • 2.2.2.1 测试环境准备
  • 2.2.2.2 基础字段解析
  • 2.2.2.3 列表、迭代器、管道
  • 2.2.2.4 复杂数据类型构建
  • 2.2.2.5 内置的操作符以及函数
  • 3. python -m json.tool


1. JSON数据格式详解

JSON(JavaScript Object Notation))是一种轻量级的数据交换格式。 便于人为阅读和编写、机器解析和生成。

1.1 两种结构

  • 对象:是一个无序的 key/value 键值对集合,一个对象以 {开始,以}结束,每个key后面跟一个:, key/value 键值对之间使用,分隔;
  • 数组:是value的有序集合,一个数组以[开始,以]结束,value之间使用,分隔;value可以是双引号内的字符串、数值、TRUE、FALSE、NULL、对象或数组;

1.2 使用范例

# 压缩
{"key1":"value1","key2":["key3","key4",{"key5":"value5","key6":"value6"}]}

# 格式化
{
	"key1": "value1",
	"key2": [
        "key3", 
        "key4", {
            "key5": "value5",
            "key6": "value6"
        }
    ]
}

2. jq

jq是stedolan开发的一个轻量级的和灵活的命令行JSON处理器,它主要用于在命令行界面处理JSON输入,并使用给定的过滤条件来过滤符合条件的新的JSON串。通常使用jq来进行JSON数据格式化过滤和处理。

2.1 安装

# 先安装epel源
$ yum install -y epel-release
# 再安装jq
$ yum install jq

2.2 jq 基础使用

2.2.1 基本语法

$ jq [options] <jq filter> [file...]
$ jq [options] --args <jq filter> [strings...]
$ jq [options] --jsonargs <jq filter> [JSON_TEXTS...]

# options 可选参数列表和说明
-c               将格式化json输出为紧凑的字符串格式;
-n               使用`null`作为单个输入值;
-e               根据输出设置退出状态代码;
-s               将所有输入读取(吸取)到数组中;应用过滤器;
-r               输出原始字符串,而不是JSON文本;
-R               读取原始字符串,而不是JSON文本;
-C               为JSON输出填充颜色;
-M               单色(不要为JSON着色);
-S               在输出上排序对象的键;
--tab            使用制表符进行缩进;
--arg a v        将变量$a设置为value<v>;
--argjson a v    将变量$a设置为JSON value<v>;
--slurpfile a f  将变量$a设置为从<f>读取的JSON文本数组;
--rawfile a f    将变量$a设置为包含<f>内容的字符串;
--args           其余参数是字符串参数,而不是文件;
--jsonargs       其余的参数是JSON参数,而不是文件;
--               终止参数处理;

# 查看更多使用指南。
$ jq --help

2.2.2 基础使用

2.2.2.1 测试环境准备
$ mkdir json
$ cd json/
$ echo '{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"pc-deployment","namespace":"dev"},"spec":{"replicas":3,"selector":{"matchLabels":{"app":"nginx-pod"}},"template":{"metadata":{"labels":{"app":"nginx-pod"}},"spec":{"containers":[{"name":"nginx","image":"nginx:1.17.1","ports":[{"containerPort":80}]}]}}}}' > ./test.json
2.2.2.2 基础字段解析
# 使用.参数默认格式化整个json数据
$ cat test.json | jq .				# 单独出现的"."可以省略
{
  "apiVersion": "apps/v1",
  "kind": "Deployment",
  "metadata": {
    "name": "pc-deployment",
    "namespace": "dev"
  },
  "spec": {
    "replicas": 3,
    "selector": {
      "matchLabels": {
        "app": "nginx-pod"
      }
    },
    "template": {
      "metadata": {
        "labels": {
          "app": "nginx-pod"
        }
      },
      "spec": {
        "containers": [
          {
            "name": "nginx",
            "image": "nginx:1.17.1",
            "ports": [
              {
                "containerPort": 80
              }
            ]
          }
        ]
      }
    }
  }
}

# 使用.$key来获取指定value
$ cat test.json | jq .apiVersion
"apps/v1"

# 解析json中的层级数据
$ cat test.json | jq .spec
{
  "replicas": 3,
  "selector": {
    "matchLabels": {
      "app": "nginx-pod"
    }
  },
  "template": {
    "metadata": {
      "labels": {
        "app": "nginx-pod"
      }
    },
    "spec": {
      "containers": [
        {
          "name": "nginx",
          "image": "nginx:1.17.1",
          "ports": [
            {
              "containerPort": 80
            }
          ]
        }
      ]
    }
  }
}
# 仅输出某个层级下的数据
$ cat test.json | jq .spec.selector.matchLabels.app
"nginx-pod"

# 获取多个字段 (使用'.filed1,.filed2' 可以获取两个字段)
$ cat test.json | jq .spec.selector.matchLabels.app,.spec.template.metadata.labels.app,.spec.template.spec.containers[].ports[].containerPort
"nginx-pod"
"nginx-pod"
80
2.2.2.3 列表、迭代器、管道
# 解析json中的数组或者列表
$ cat test.json | jq .spec.template.spec.containers
[
  {
    "name": "nginx",
    "image": "nginx:1.17.1",
    "ports": [
      {
        "containerPort": 80
      }
    ]
  }
]

# 支持索引检查,比如.array[index],索引从0开始,-n为倒数第n个元素
$ cat test.json | jq .spec.template.spec.containers[0]
{
  "name": "nginx",
  "image": "nginx:1.17.1",
  "ports": [
    {
      "containerPort": 80
    }
  ]
}
# 支持索引范围检查,比如.array[index_src:index_dst]
cat test.json | jq .spec.template.spec.containers[0:3]
[
  {
    "name": "nginx",
    "image": "nginx:1.17.1",
    "ports": [
      {
        "containerPort": 80
      }
    ]
  }
]

# value迭代器.[],[]为全部范围,此时可以省略
$ cat test.json | jq .spec.template.spec.containers[]
{
  "name": "nginx",
  "image": "nginx:1.17.1",
  "ports": [
    {
      "containerPort": 80
    }
  ]
}

# 管道,在jq的表达式中,可以使用管道符号"|"来对前面的表达式结果进行再次处理
$ cat test.json | jq '.spec.template.spec.containers[]|.name'
"nginx"
# 使用管道符合时必须使用引号,否则Linux会识别为命令
$ cat test.json | jq .spec.template.spec.containers[]|.name 
bash: .name: command not found...

# 值的计算 
echo '{"num":12}' | jq '(.num +2)*1024'
14336
2.2.2.4 复杂数据类型构建
  • 列表 (数组) 构建 []: 可以将输出字符返回成一个列表 (可以结合多字段使用)
  • 对象构建 {}: 可以联合()构建新的 json 对象
  • {} 可以通过字段构建新的 json 结构,比如 {user, title: .titles[]} 表示将 titles 数组中的元素迭代出来后和 user 字段重新组成多个 json 字串
  • () 可以用于直接将 value 作为 key,比如 {(.user): .titles} 可以直接构建无声明 key 的 json 串
  • 递归下降..: 可以递归下降,将字符串的每一个 value 都迭代出来,用法和内置的 recurse 函数相似
# 数组构建
$ cat test.json | jq '[.spec.selector]'
[
  {
    "matchLabels": {
      "app": "nginx-pod"
    }
  }
]

$ cat test.json | jq [.spec.replicas,.spec.template.metadata.labels.app]
[
  3,
  "nginx-pod"
]


# 批量计算
$ echo '{"num": [1,2,3,4]}' | jq '[.num[] | . * 2 ]'
[
  2,
  4,
  6,
  8
]


# 对象构建
$ cat test.json | jq '{apiVersion,kind,name:.spec.template.spec.containers[].name,image:.spec.template.spec.containers[].image}'
{
  "apiVersion": "apps/v1",
  "kind": "Deployment",
  "name": "nginx",
  "image": "nginx:1.17.1"
}

# 构建无声明key的json数据,key = (.kind)
$ cat test.json | jq '{apiVersion,name:.spec.template.spec.containers[].name,(.kind):.spec.template.spec.containers[].image}'
{
  "apiVersion": "apps/v1",
  "name": "nginx",
  "Deployment": "nginx:1.17.1"
}

# 递归下降,使用..可以将全部的子串解析出来,直到最后的叶子value
$ echo '[[{"a":1}]]' | jq '.. '
[
  [
    {
      "a": 1
    }
  ]
]
[
  {
    "a": 1
  }
]
{
  "a": 1
}
1

# 递归下降获取具体的值'.. | .filed',获取key包含a的值
$ echo '[[{"a":1}]]' | jq '.. | .a?'
1
2.2.2.5 内置的操作符以及函数
  • +:两个过滤器相加,支持Numbers、Arrays、Strings、Objects类型;
  • -:相减,用法同上;
  • *,/,%:乘除余运算;
  • length:获取不同类型值的长度,支持string,array,object,null(zero);
  • utf8bytelength:utf8的字节长度;
  • keyskeys_unsorted: 获取最外层的key以及排序之后的key,如果是列表或者数组,将返回索引;
  • has(key):返回json中是否包含key,或者数组/列表中是否包含索引下标(需要注意的是,如果需要解析
    析数组/列表内部的子串是否包含某个key,需要先使用map函数;
  • in(object): 判断json中是否包含object中给定的key;
  • max(x)map_values(x): 使用过滤器x对输入数组的元素进行挨个计算,并返回新数组;后者是给值进行计算;
  • path(path_expression): 输出给定路径表达式中的数组表示;
  • del(path_expression): 删除路径表达式中的filed;
  • getpath(PATHS): 获取指定路径的索引;
  • setpath(PATHS; VALUE): 给指定路径设置新的值;
  • delpaths(PATHS): 删除指定路径;
  • to_entries, from_entrieswith_entries: 二次处理 json 实体,比如从[{key:k1,value: v1}{key:k2,value:v2} ] 转换成 {k1:v1,k2:v2}
  • select(boolean_expression):使用bool表达式进行条件过滤;
  • arrays objectsiterablesbooleansnumbersnormalsfinitesstringsnullsvalues, scalars:分别只选择数组、对象、可迭代对象 (数组或对象)、布尔值、数字、普通数字、有限数字、字符串、空值、非空值和不可迭代对象的输入;
  • add: 过滤器 add 接受一个数组作为输入,并将数组的元素加在一起作为输出。这可能意味着根据输入数组元素的类型进行求和、连接或合并 —— 规则与上面描述的+运算符的规则相同;
  • anyall:从数组或者列表中判断是否存在或者全部存在;
  • range:对象生成器;
  • floor:输出数字的低阶值;
  • sqrt:求开方;
  • tonumber:字符串转数字;
  • tostring:数字转字符串;
  • type: 获取元素类型;
  • sortsort_by(path_expression):排序;
  • unique, unique_by(path_exp):去重;
  • reverse:反转;
  • contains(element):判断是否包含;
  • startswith(str):判断前缀;
  • endswith(str):判断后缀;
  • split(str):字符串转列表;
  • join(str):列表转字符串;
  • while(cond; update):条件判断;
  • until(cond; next):条件判断;
  • (foo):引用 foo 的值;
  • tojsonfromjson:从原始字符串转到 json 或者从 json 转到原始字符串;
  • @base64@base64d:base64 编码和解码;
  • @uri@csv:生成 uri,以及表格格式。
# keys
$ cat test.json | jq 'keys'
[
  "apiVersion",
  "kind",
  "metadata",
  "spec"
]

# keys_unsorted
$ cat test.json | jq 'keys_unsorted'
[
  "apiVersion",
  "kind",
  "metadata",
  "spec"
]

# has
$ cat test.json | jq '.spec | has("replicas")'
true

$ cat test.json | jq 'has("replicas")'
false
$ cat test.json | jq 'has("spec")'
true

# to_entries, from_entries, with_entries
$ cat test.json | jq '.spec | to_entries'
[
  {
    "key": "replicas",
    "value": 3
  },
  {
    "key": "selector",
    "value": {
      "matchLabels": {
        "app": "nginx-pod"
      }
    }
  },
  {
    "key": "template",
    "value": {
      "metadata": {
        "labels": {
          "app": "nginx-pod"
        }
      },
      "spec": {
        "containers": [
          {
            "name": "nginx",
            "image": "nginx:1.17.1",
            "ports": [
              {
                "containerPort": 80
              }
            ]
          }
        ]
      }
    }
  }
]

# select(bool_exp)
$ cat test.json | jq '. | select(.kind == "Deployment")'
{
  "apiVersion": "apps/v1",
  "kind": "Deployment",
  "metadata": {
    "name": "pc-deployment",
    "namespace": "dev"
  },
  "spec": {
    "replicas": 3,
    "selector": {
      "matchLabels": {
        "app": "nginx-pod"
      }
    },
    "template": {
      "metadata": {
        "labels": {
          "app": "nginx-pod"
        }
      },
      "spec": {
        "containers": [
          {
            "name": "nginx",
            "image": "nginx:1.17.1",
            "ports": [
              {
                "containerPort": 80
              }
            ]
          }
        ]
      }
    }
  }
}

# @base64/@base64d
$ cat test.json | jq '.apiVersion '
"apps/v1"
$ cat test.json | jq '.apiVersion | @base64'
"YXBwcy92MQ=="
$ cat test.json | jq '.apiVersion | @base64 | @base64d'
"apps/v1"

3. python -m json.tool

若Linux系统无法下载jq工具,可以使用默认python工具包中的json.tool做JSON数据格式化操作(部分操作系统使用的是python3版本),与等同于jq -M不着色显示。

$ cat test.json | python -m json.tool
{
    "apiVersion": "apps/v1",
    "kind": "Deployment",
    "metadata": {
        "name": "pc-deployment",
        "namespace": "dev"
    },
    "spec": {
        "replicas": 3,
        "selector": {
            "matchLabels": {
                "app": "nginx-pod"
            }
        },
        "template": {
            "metadata": {
                "labels": {
                    "app": "nginx-pod"
                }
            },
            "spec": {
                "containers": [
                    {
                        "image": "nginx:1.17.1",
                        "name": "nginx",
                        "ports": [
                            {
                                "containerPort": 80
                            }
                        ]
                    }
                ]
            }
        }
    }
}