shell jq处理json字符串

发布时间 2023-05-06 13:06:10作者: G先生

1.1 工具介绍

自己用shell处理json字符串的时候,开发输入格式的不通会导致解析字符串有问题,所以这里用到了jq工具
jq 是一款命令行下处理 JSON 数据的工具。其可以接受标准输入,命令管道或者文件中的 JSON 数据,经过一系列的过滤器(filters)和表达式的转后形成我们需要的数据结构并将结果输出到标准输出中。jq 的这种特性使我们可以很容易地在 Shell 脚本中调用它。

2.1 安装jq

  • macos
brew install jq
  • linux
 wget https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
 chmod a+x jq-linux64 && mv jq-linux64 /usr/bin/jq
  • centos
yum install epel-release
yum install jq

3.1 jq表达式

3.1.1 选项

  • '-r'选项。
    该选项控制 jq 是输出 raw 格式内容或 JSON 格式内容。所谓的 JSON 格式是指符合 JSON 标准的格式。例如,假设我们要查询 JSON 字符串{"name":"tom"}中 name 的值. 使用-r 选项时返回的是'tom'. 不使用-r 选项时,返回的是'"tom"'.返回值多了一对双引号。
  • -s 选项。
    jq 可以同时处理空格分割的多个 JSON 字符串输入。默认情况下,jq 会将 filter 分别对每个 JSON 输入应用,并返回结果。使用-s 选项,jq 会将所有的 JSON 输入放入一个数组中并在这个数组上使用 filter。"-s"选项不但影响到 filter 的写法。如果在 filter 中需要对数据进行选择和映射,其还会影响最终结果。
  • --arg 选项。
    jq 通过该选项提供了和宿主脚本语言交互的能力。该选项将值(v)绑定到一个变量(a)上。在后面的 filter 中可以直接通过变量引用这个值。例如,filter '.$a'表示查询属性名称等于变量 a 的值的属性。 
echo '{"name":"voidking"}' | jq .
 
//这样输出的不带""
 
echo '{"name":"voidking"}' | jq .name
 
//这样输出的带 ""
 
echo '{"name":"voidking"}' | jq -r .name

 

3.1.2 获取key,value

cat aaa.txt
 
{"redis_host": "192.168.160.38","redis_port": "6666"}
 
//获取所有的key,并且不带""
 
cat aaa.txt | jq keys[]
 
//获取所有的key,并且带""
 
cat aaa.txt | jq -r keys[]
 
 
 
//获取key值为redis_host对应的value,并且带""
 
cat aaa.txt |jq -r .redis_host

 

3.1.3 串行操作

jq表达式支持串行化操作。一个复杂的表达式可以由多个简单的表达式组成,以管道符号 | 分割,串行化执行。管道前面表达式的输出,是管道后面表达式的输入。

逗号 , 表示对同一个输入应用多个表达式。

 
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq .name.firstname
 
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.name | .firstname'
 
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.name | .firstname,.lastname'
 
echo '[{"firstname":"Void","lastname":"King"},{"firstname":"Hao","lastname":"Jin"}]' | jq '.[] | .firstname,.lastname' | sed -n "N;s/\n/ /p"

 

获取串行json的key

$ cat test.json
{
  "a": "aa",
  "b": "bb",
  "c": {
      "dd": "ddd",
      "ee": "eee"
  }
}
 
 
//获取根级别的keys:
$ jq -r keys[] test.json 
a
b
c
 
 
获取下层成员的keys:
$ jq .c test.json | jq -r keys[]
dd
ee

 

3.1.4 数组操作

echo '[{"name":"voidking"},{"name":"haojin"}]' | jq .
 
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[]'
 
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[0:2]'
 
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[0,1]'
 
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[].name'
 
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[] | .name'
 
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.[] | .["name"]'

 

3.1.5 jq运算

echo '{"num":3,"str":"343"}' | jq '.num*3'
 
echo '{"num":3,"str":"343"}' | jq '.num/3'
 
 
 
echo '{"num":3,"str":"343"}' | jq '.str+"3"'
 
echo '{"num":3,"str":"343"}' | jq '.str*3'
 
echo '{"num":3,"str":"343"}' | jq '.str/"4"'
 
 
 
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.+[{"name":"voidking"}]'
 
echo '[{"name":"voidking"},{"name":"haojin"}]' | jq '.-[{"name":"voidking"}]'
 
 
 
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.+{"name":{"nickname":"Hankin"}}'
 
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.*{"name":{"nickname":"Hankin"}}'
 
 
 
echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq '.name.nickname//"Hankin"'
 
 
 
jq -n '([1,2]|.[])+([4,6]|.[])'

 

3.1.6 删除

echo '{"name":{"firstname":"Void","lastname":"King"}}' | jq 'del(.name.firstname)'

 

3.1.7 映射

在数据处理过程中,我们经常需要将数据从一种形式转换成另外一种形式,或者改变数据的值。
jq提供了两个内置映射函数来实现这种转换:map 和 map_values。其中,map处理的对象是数组,而map_values则处理对象属性的值。map 函数的参数为 filter 表达式。

echo '[1,2,3,4]'| jq -r 'map(.+1)'

 

3.1.8 过滤

echo '[1,2,3,4]'| jq -r 'map(select(.>2))'
 
echo '[1,2,3,4]'| jq -r '.[]|select(.>2)'
 
echo '[{"name":"voidking","age": 18},{"name":"haojin","age": 28}]' | jq '.[]|select(.name=="haojin")'

 

3.1.9 数组函数

jq 提供内置函数用于完成数组的扁平化(flatten),反序(reverse),排序(sort、sort_by),比较(min、min_by、max、max_by)和查找(indices、index、rindex)。其中indices函数的输入数据可以是数组,也可以是字符串。和 index函数不同的是,其结果是一个包含所有参数在输入数据中位置的数组。

 
jq -nr '[1,[2,3],4]|flatten'
 
jq -nr '[1,2,3]|reverse'
 
jq -nr '[3,1,2]|sort'
 
jq -nr '[{"a":1},{"a":2}]|sort_by(.a)'
 
jq -nr '"abcb"|indices("b")'
 
jq -nr '[1,3,2,3]|indices(3)'

 

3.1.10 路径

jq中的path是指从根到某个叶子属性的访问路径。
在jq中有两种表示路径的方式:数组表示法和属性表示法。
属性表示法类似于我们在filter中访问某个属性值的方式,如.a.b。
数组表示法是将路径中的每一部分表示为数组的一个元素。
jq提供了一个内置函数path用来实现路径从属性表示法到数组表示法的转换。

jq还提供了函数用来读取路径的值(getpath), 设置路径的值(setpath)和删除路径(del)。
不过这三个函数对路径的处理并不一致。其中getpath和setpath只接受数组表示法的路径,而del函数只能正确处理属性表示法的路径。

jq还提供了一个函数paths用来枚举可能存在的路径。在没有参数的情况下,paths函数将输出JSON数据中所有可能的路径。paths函数可以接受一个过滤器,来只输出满足条件的路径。

jq中提供了一系列的函数用来判断某个元素或者属性是否存在于输入数据中。其中函数has和in用来判断JSON对象或数组是否包含特定的属性或索引。函数contains和inside用来判断参数是否完全包含在输入数据中。对于不同的数据类型,判断是否完全包含的规则不同。对于字符串,如果A是B的子字符串,则认为A完全包含于B。对于对象类型,如果对象A的所有属性在对象B中都能找到且值相同,则认为A完全包含于B。