jq工具的使用

jq 命令行行为的完整规则

命令格式行为示例结果
jq (无任何参数) 显示帮助信息 jq 显示帮助文档
jq <选项> (无过滤器) 显示帮助信息 jq -c
jq -n
显示帮助文档
jq <过滤器> 阻塞等待输入 jq '.'
jq 'map(.id)'
等待 STDIN
jq <选项> <过滤器> 取决于选项:
- 普通选项:等待输入
-n:不等待
jq -c '.' → 等待
jq -n '.' → 立即执行
 
jq <过滤器> 文件 立即处理文件 jq '.' data.json 处理文件内容
jq <选项> <过滤器> 文件 立即处理文件 jq -c '.' data.json 处理文件内容

1. 只有选项 → 显示帮助

$ jq -c
jq - commandline JSON processor [version 1.6]
Usage: jq [options] <jq filter> [file...]
...
# 立即显示帮助文档,不阻塞

2. 只有过滤器 → 阻塞等待

$ jq '.name'
(光标闪烁,程序挂起等待输入)
# 需要按 Ctrl+D 结束输入或 Ctrl+C 终止

3. 过滤器 + -n → 立即执行

$ jq -n '.name'
null  # 立即输出结果(因为没有输入)

4. 过滤器 + 文件 → 立即处理

$ jq '.name' data.json
"Alice"  # 立即从文件处理

为什么这个区别很重要?

在实际脚本编写中:

#!/bin/bash

# 危险:会阻塞脚本执行!
result=$(jq '.data')

# 安全:立即生成数据
result=$(jq -n '{time: now}')

# 安全:从变量读取
json='{"value": 42}'
result=$(jq '.value' <<< "$json")

基本操作:

jq [options] <jq filter> [file...]

[options] - 可选选项

  • -r:原始输出模式

  • -c:紧凑输出

  • -n:无输入模式

 <jq filter> - 必填过滤器

:用单引号包裹的表达式 '...'

  • '.':恒等过滤器

  • '.name':字段选择器

  • 'map(.id)':数组处理

[file...] - 可选输入文件

  • 格式:文件路径(一个或多个)

    • data.json:单个文件

    • file1.json file2.json:多个文件

 

输入jq .后阻塞,然后我键盘输入a,报parse error: invalid numeric literal at line2,column 0,为啥报这个错误

  • jq 进入等待输入状态(因为没有使用 -n 选项且没有提供文件)

  • 光标在终端闪烁,等待您输入 JSON 数据

jq 要求输入必须是有效的 JSON,而 a 不是合法的 JSON。有效的 JSON 值必须是:

  • 字符串:"a"(必须用双引号包裹)

  • 数字:123

  • 布尔值:true 或 false

  • 对象:{"key": "value"}

  • 数组:[1, 2, 3]

  • null:null

虽然您输入的是字母,但 jq 的解析器是这样工作的:

  1. 首先尝试解析为数字(因为数字是 JSON 的基本类型)

  2. 当看到 a 时,它可能期待类似 0xA 的十六进制数字

  3. 发现后面没有有效数字字符时抛出错误

 

 

1. JSON 格式要求 jq 要求输入必须是有效的 JSON,而 a 不是合法的 JSON。有效的 JSON 值必须是: 字符串:"a"(必须用双引号包裹) 数字:123 布尔值:true 或 false 对象:{"key": "value"} 数组:[1, 2, 3] null:null 不对吧,json不是key,value么,只输入上面的值也不是json啊?

真正的JSON格式要求:

  1. 顶层必须是以下之一:

    • 对象(用 {} 包裹)

    • 数组(用 [] 包裹)

  2. 值类型:

    • 字符串:必须双引号包裹 "text"

    • 数字:整数或浮点数 423.14

    • 布尔值:true 或 false

    • 空值:null

    • 对象:{"key": "value"}

    • 数组:[1, 2, 3]

 

然JSON标准要求顶层必须是对象或数组,但jq对输入的处理更灵活:

  1. jq接受任何有效的JSON值作为输入,包括:

    • 简单值:"string"42truenull

    • 复合值:{...}[...]

  2. 这是jq的特性,不是JSON标准的特性:

    # 这些在jq中都是有效的输入
    echo '"text"' | jq .  # 字符串
    echo '42' | jq .      # 数字
    echo 'true' | jq .    # 布尔值

为什么jq允许简单值?

这是jq设计者的选择:

  1. 实用主义:很多场景只需要处理简单值

  2. 管道友好:便于在命令行中处理各种数据

  3. 符合脚本需求:例如 jq -n '1 + 1' 直接计算

标准JSON vs jq输入对比

类型标准JSON是否有效jq是否接受作为输入
{"key": "value"}
["a", "b"]
"string" ❌(顶层无效)
42 ❌(顶层无效)
true ❌(顶层无效)
null ❌(顶层无效)
a

 

json的key必须是字符串,value是上面几种数据类型?

JSON 格式的完整规范

  1. 顶层结构:

    • 必须是对象({})或数组([]

    • 不能是简单值(字符串、数字、布尔值或 null)

  2. 键(Key)要求:

    • 必须是字符串

    • 必须用双引号包裹

    • 不能是数字、布尔值或其他类型

    // 正确
    {"name": "Alice"}
    
    // 错误 - 键未加引号
    {name: "Alice"}
    
    // 错误 - 键是数字
    {42: "answer"}
  3. 值(Value)类型:

    类型示例说明
    字符串 "text" 必须双引号包裹
    数字 423.14 整数或浮点数
    布尔值 truefalse 必须小写
    数组 [1, "two", true] 有序值集合
    对象 {"key": "value"} 键值对集合
    null null 表示空值

虽然标准 JSON 要求顶层必须是对象或数组,但 jq 放宽了这个限制:

  1. jq 接受简单值作为输入:

    # 这些在 jq 中有效但不符合 JSON 标准
    echo '"text"' | jq .  # 字符串
    echo '42' | jq .      # 数字
    echo 'true' | jq .    # 布尔值
  2. 但键仍然必须遵循 JSON 规范:

    # 尝试使用无效键
    echo '{name: "Alice"}' | jq .
    # 报错:parse error: Invalid numeric literal at line 1
    
    # 正确写法
    echo '{"name": "Alice"}' | jq .

# 查看特定主机的 facts

ansible 172.17.79.16 -i hosts -m setup -o 2>/dev/null | awk-F '=> ''{print $2}'| jq .

 

或者ansible 172.17.79.16 -i hosts -m setup -o 2>/dev/null | tr -d "172.17.79.16 | success => "| less

  1. 对于数组:使用索引访问 .[0].[1]

  2. 对于对象:使用键名访问 .["key"] 或 .key

  3. keys 函数适用于两种结构:

    • 数组 → 返回索引

    • 对象 → 返回键名

  4. 组合使用管道 | 可以构建复杂查询

这两种访问方式是 jq 处理 JSON 的核心功能,掌握它们就能高效提取和转换 JSON 数据

 

 the simplest filter is .,which is the identity filter

在jq工具中,.(点号)是最简单的过滤器,称为"identity filter"(恒等过滤器)。它的作用是将输入的JSON数据原样输出,仅对格式进行标准化处理(如美化缩进)

identity‌(恒等)这一术语源自数学和计算机科学中的概念,指代一种不改变输入数据的操作,词根"ident"源于拉丁语"idem"(相同)48,后缀"-ity"表示性质或状态,组合后表示"同一性"或"不变性",如同身份证(identity card)唯一对应个人身份,区别于动词"identify"(识别)的动态过程,此处强调静态的"同一性"

 

例1:

 

jq '.[0] | keys' array_of_objects.json

array_of_objects.json 内容:

[
  {"id": 1, "name": "Alice", "active": true},
  {"id": 2, "email": "bob@example.com"},
  {"role": "admin", "permissions": ["read", "write"]}
]

  1. .[0] 获取数组的第一个元素 {"id":1,"name":"Alice","active":true}

  2. keys 提取这个对象的所有键名(按字母排序)

  

例2:.[]在数组和字典(对象)中的展开不同

对象的展开:
a.json的内容如下:
{ "id": 1, "name": "Alice", "roles": ["admin", "user"] }
 
命令jq '.[] | keys' a.json:
'.[]' a.json 展开的字典的value
结果:
1
Alice
["admin", "user"]


{"user": {"name": "Alice", "age": 30}, "server": {"ip": "1.1.1.1"}}
jq '.[] | keys' file.json

输出:

["age","name"]
["ip"]




数组的展开:
假设你的 file.json:

[
{
"id": 1,
"name": "Alice",
"roles": ["admin", "user"]
},
{
"id": 2,
"name": "Bob",
"email": "bob@example.com"
},
{
"company": "Tech Inc",
"country": "USA"
}
]

  1. .[]:展开数组中的所有元素

    {"id":1,"name":"Alice","roles":["admin","user"]}
    {"id":2,"name":"Bob","email":"bob@example.com"}
    {"company":"Tech Inc","country":"USA"}
  2. | keys:对每个展开的对象获取键名

    ["id","name","roles"]
    ["id","name","email"]
    ["company","country"]
最终输出:

[
"id",
"name",
"roles"
]
[
"id",
"name",
"email"
]
[
"company",
"country"
]

.[] - 数组展开运算符

  • 作用:将数组拆分为独立的元素

  • 输入:[元素1, 元素2, ...]

  • 输出:元素1 元素2  ...(多个独立 JSON 对象)

  • 如果输入是对象:{"a":1, "b":2} → 输出值 1 2


  

jq '.object.nested_array[].property' file.json

.object # 第一层:访问根对象的 "object" 属性
.nested_array # 第二层:访问 object 对象的 "nested_array" 属性
[] # 解包操作:将 nested_array 数组展开为多个元素
.property # 第三层:访问每个数组元素的 "property" 属性

 

假设你的 file.json 内容
{
  "object": {
    "nested_array": [
      {
        "id": 1,
        "property": "value1",
        "details": {"sub": "a"}
      },
      {
        "id": 2,
        "property": "value2",
        "details": {"sub": "b"}
      }
    ],
    "other_field": "ignored"
  },
  "unrelated": "data"
}    

  

运行命令:

jq '.object.nested_array[].property' file.json

输出:

"value1"
"value2"

关键概念解释

    1. . (根选择器)

      • 起始点,表示整个 JSON 文档的根

      • 类似文件系统的 / 根目录

    2. .object (属性访问)

      • 访问根对象的 object 属性

      • 等价于 JavaScript 的 data.object

    3. .nested_array (嵌套访问)

      • 访问 object 对象的 nested_array 属性

      • 类似 data.object.nested_array

    4. [] (数组迭代器)

      • 最关键的操作符:将数组展开为独立的元素

      • 输入:[ {...}, {...} ]
        输出:{...} 和 {...}(两个独立对象)

    5. .property (叶节点访问)

      • 从每个展开的数组元素中提取 property 值

      • 对每个元素执行:element.property

类比其他语言

jq 表达式JavaScript 等价Python 等价
.object data.object data['object']
.nested_array[] data.object.nested_array.forEach(...) for item in data['object']['nested_array']:
.property item.property item['property']



# 查看特定主机的 facts

ansible 172.17.79.16 -i hosts -m setup -o 2>/dev/null | awk-F '=> ''{print $2}'| jq .

或者ansible 172.17.79.16 -i hosts -m setup -o 2>/dev/null | tr -d "172.17.79.16 | success => "| less

如果ansible输出的不是单行(比如没有使用`-o`选项),那么上述命令可能会失败,因为ansible默认输出的JSON是带缩进的多行格式,
而awk是按行处理的,这样每行都会被分割,导致输出多行内容给jq,而jq期望输入是一个完整的JSON文档。
    1. ansible ... -o
      -o 参数使输出为单行(关键!)

       
      172.17.79.16 | SUCCESS => {JSON数据}
    2. awk -F'=> ' '{print $2}'
      以 "=> " 为分隔符,提取第二部分(纯JSON)

    3. jq .
      美化输出 JSON



shell中的数组arr=(a b c d)
echo ${a[0]}

declare -A arr1=([0]=a [1]=b [2]=c [3]=d)
echo ${b[0]}
结果一样,有啥区别,难道普通数组可以看作关联数组的特殊数组?

是的,索引数组可以看作关联数组的特殊形式(键为连续整数),但在 Shell 实现中它们是不同的数据结构:

  • 索引数组:为顺序访问优化的数组

  • 关联数组:通用的键值存储

在您的例子中,当使用连续整数作为关联数组的键时,行为确实类似于索引数组,但底层实现和特性仍有差异。


因X.Y和X["Y"]都行,所以
ansible 172.17.69.16 -i hosts -m setup --key-file=./ssh/id_rsa -o 2>/dev/null | \
awk -F "=> " '{print $2}'|jq '.ansible_facts.ansible_nodename'
等价于
ansible 172.17.69.16 -i hosts -m setup --key-file=./ssh/id_rsa -o 2>/dev/null | \
awk -F "=> " '{print $2}'|jq '.["ansible_facts"]["ansible_nodename"]'
.是文本对象

查看ansible_facts所有key
ansible 172.17.69.16 -i hosts -m setup --key-file=./ssh/id_rsa -o 2>/dev/null | \
awk -F "=> " '{print $2}'|jq '.[]'

ansible 172.17.69.16 -i hosts -m setup --key-file=./ssh/id_rsa -o 2>/dev/null | \
awk -F "=> " '{print $2}'|jq '.ansible_facts|keys'


 

posted @ 2025-07-09 15:37  _java_python  阅读(25)  评论(0)    收藏  举报
       [00:00.000] 作词 : 陈信荣
    [00:01.000] 作曲 : 周传雄
    [00:02.000] 编曲 : 周传雄
    [00:03.000] 制作人 : 周传雄
    [00:29.259]过完整个夏天
    [00:34.742]忧伤并没有好一些
    [00:41.185]开车行驶在公路无际无边
    [00:47.320]有离开自己的感觉
    [00:52.453]
    [00:53.347]唱不完一首歌
    [00:59.370]疲倦还剩下黑眼圈
    [01:05.596]感情的世界伤害在所难免
    [01:11.703]黄昏再美终要黑夜
    [01:18.292]依然记得从你口中说出再见坚决如铁
    [01:24.732]昏暗中有种烈日灼身的错觉
    [01:30.171]黄昏的地平线
    [01:33.230]划出一句离别
    [01:36.313]爱情进入永夜
    [01:42.165]
    [01:42.881]依然记得从你眼中滑落的泪伤心欲绝
    [01:49.290]混乱中有种热泪烧伤的错觉
    [01:54.774]黄昏的地平线
    [01:57.816]割断幸福喜悦
    [02:00.915]相爱已经幻灭
    [02:07.171]
    [02:19.647]唱不完一首歌
    [02:25.497]疲倦还剩下黑眼圈
    [02:31.753]感情的世界伤害在所难免
    [02:37.881]黄昏再美终要黑夜
    [02:42.994]
    [02:44.363]依然记得从你口中说出再见坚决如铁
    [02:50.872]昏暗中有种烈日灼身的错觉
    [02:56.291]黄昏的地平线
    [02:59.393]划出一句离别
    [03:02.507]爱情进入永夜
    [03:08.340]
    [03:09.205]依然记得从你眼中滑落的泪伤心欲绝
    [03:15.531]混乱中有种热泪烧伤的错觉
    [03:20.937]黄昏的地平线
    [03:23.991]割断幸福喜悦
    [03:27.025]相爱已经幻灭
    [03:34.375]
    [03:58.563]依然记得从你口中说出再见坚决如铁
    [04:04.694]昏暗中有种烈日灼身的错觉
    [04:10.141]黄昏的地平线
    [04:13.156]划出一句离别
    [04:16.228]爱情进入永夜
    [04:21.297]
    [04:22.863]依然记得从你眼中滑落的泪伤心欲绝
    [04:29.401]混乱中有种热泪烧伤的错觉
    [04:34.714]黄昏的地平线
    [04:37.774]割断幸福喜悦
    [04:40.913]相爱已经幻灭
    [05:39.200] 配唱制作人 : 吴佳明
    [05:39.533] 钢琴 : 周传雄
    [05:39.866] 吉他 : 许华强
    [05:40.199] 鼓 : Gary Gideon
    [05:40.532] 贝斯 : Andy Peterson
    [05:40.865] 弦乐编写 : 吴庆隆
    [05:41.198] 弦乐 : 孔朝晖/顾文丽/隋晶晶/梁中枢/尹淑占/王言/关旗
    [05:41.531] 和声编写 : 周传雄
    [05:41.864] 和声 : 周传雄
    [05:42.197] 录音师 : 林世龙/沈文钏/Geoffrey Lee
    [05:42.530] 混音师 : 王晋溢
    [05:42.863] 录音室 : 强力/HASAYAKE/Atomic & Audioplex (Singapore)
    [05:43.196] 混音室 : 白金
    [05:43.529] OP : Sony/ATV Music Publishing Taiwan/哈萨雅琪有限公司
    [05:43.862] SP : Sony/ATV Music Publishing Taiwan​