Jq¶
简介¶
jq 是一个命令行 JSON 处理器
安装¶
# Windows
scoop install jq
使用¶
jq 使用路径访问 JSON 中的字段,并且可以一直嵌套下去
.表示整个文件.attr如果是对象,表示对象的 attr 字段.[]如果是数组,表示数组的所有元素.[1]如果是数组,表示数组第 2 个索引的元素.attr.value表示 attr 字段的 value 字段
jq 有自己的语言(就像 awk 那样),支持函数等高级编程特性,详细说明请阅读 官方文档。
查询¶
# 输出 114514
echo '{ "num1": 114514, "num2": 1919180 }' | jq '.num1'
# 输出 1919180
echo '[ 114514, 1919180 ]' | jq '.[1]'
修改¶
# 输出 { "num1": 123456, "num2": 1919180 }
echo '{ "num1": 114514, "num2": 1919180 }' | jq '.num1 = 123456'
# 将输出写入新文件
cat old.json | jq '.key = "value"' > new.json
脚本¶
# 运行 script.jq 中的查询/修改
cat data.json | jq -f script.jq
jq 语言是有模块系统的,可以跨文件进行代码复用。只需在文件开头写上
# 导入 utils.jq
include "utils";
# 导入 utils.jq 但使用别名
import "utils" as u;
就会自动将 utils.jq 作为模块加载进来。如果导入使用了别名,需要借助 NAME::xxx 来使用模块。
示例¶
jq 处理 JSON 数据要比传统的 awk/sed 方便许多。下面展示一些我自己实际使用 jq 的场景。
我想要知道 Scoop 的某个包有哪些二进制文件,会不会和 PATH 中已存在的程序冲突。这时可以直接查询 manifest 文件
scoop cat xxxx | jq '.bin.[]'
# 如果输出有路径前缀,进行去除
scoop cat coreutils | jq '.bin.[] | sub(".*\\\\"; null)'
# 如果输出混合了多种类型,进行筛选和预处理
scoop cat unxutils | jq '.bin.[] | strings | sub(".*\\\\"; null)'
scoop cat uutils-coreutils | jq '.bin[] | arrays | last'
# 得到纯净的输出后就可以开始后续处理了
scoop cat xxx | jq '...' | tr -d '\r' | xargs which
我要为 MAA 准备搓玉/不搓玉、卖玉/不卖玉共 4 份基建配置,但其实这些配置只有几处不同。此时可以选一个配置作为基准来衍生出别的配置。这样修改就能用简单的脚本进行同步,避免遗漏而导致的错误。
首先编写转换脚本
# convert-to-both.jq
# 将 不搓玉/不卖玉 转换为 搓玉/卖玉
def update_description:
.description = "搓玉/卖玉";
def update_manufacture($index; $operators):
.rooms.manufacture[$index].product = "Originium Shard" |
.rooms.manufacture[$index].operators = $operators;
def update_trading($index):
.rooms.trading[$index].product = "Orundum";
update_description |
.plans |= map(
update_description |
if .name == "早班" then
update_manufacture(0; ["艾雅法拉", "地灵", "炎熔"]) |
update_trading(0)
elif .name == "晚班" then
update_manufacture(0; ["火神", "泡泡", "褐果"]) |
update_trading(0)
end
)
然后执行转换
jq -f both.jq my-243-2-normal.json > my-243-2-both.json
可以借助模块来提高代码的复用性
# utils.jq
def update_description($description):
.description = $description;
def update_manufacture($index; $operators):
.rooms.manufacture[$index].product = "Originium Shard" |
.rooms.manufacture[$index].operators = $operators;
def update_trading($index):
.rooms.trading[$index].product = "Orundum";
# both.jq
include "utils";
update_description("搓玉/卖玉") |
.plans |= map(
update_description("搓玉/卖玉") |
if .name == "早班" then
update_manufacture(0; ["艾雅法拉", "地灵", "炎熔"]) |
update_trading(0)
elif .name == "晚班" then
update_manufacture(0; ["火神", "泡泡", "褐果"]) |
update_trading(0)
end
)
# make.jq
include "utils";
update_description("搓玉/不卖玉") |
.plans |= map(
update_description("搓玉/不卖玉") |
if .name == "早班" then
update_manufacture(0; ["艾雅法拉", "地灵", "炎熔"])
elif .name == "晚班" then
update_manufacture(0; ["火神", "泡泡", "褐果"])
end
)
# sale.jq
include "utils";
update_description("不搓玉/卖玉") |
.plans |= map(
update_description("不搓玉/卖玉") |
if .name == "早班" then
update_trading(0)
elif .name == "晚班" then
update_trading(0)
end
)
我有一个 JSON 格式的书签 bookmarks.json
{
"bookmarks": [
{
"title": "前言",
"page": 2
},
{
"title": "目录",
"page": 11
},
{
"title": "第 1 章 引言",
"page": 16,
"kids": [
{
"title": "1.1 异构并行计算",
"page": 17
},
{
"title": "1.2 现代 GPU 的体系结构",
"page": 21
},
{
"title": "1.3 为什么需要更高的速度和并行化",
"page": 23
},
{
"title": "1.4 应用程序的加速",
"page": 24
},
{
"title": "1.5 并行编程语言和模型",
"page": 26
},
{
"title": "1.6 本书的总体目标",
"page": 27
},
{
"title": "1.7 本书的组织结构",
"page": 28
},
{
"title": "参考文献",
"page": 31
}
]
},
{
"title": "第 2 章 GPU 计算的发展历程",
"page": 34,
"kids": [
{
"title": "2.1 图形流水线的发展",
"page": 34,
"kids": [
{
"title": "2.1.1 固定功能的图形流水线时代",
"page": 35
},
{
"title": "2.1.2 可编程实时图形流水线的发展",
"page": 38
},
{
"title": "2.1.3 图形与计算结合的处理器",
"page": 40
}
]
},
{
"title": "2.2 GPGPU:一个中间步骤",
"page": 42
},
{
"title": "2.3 GPU 计算",
"page": 43,
"kids": [
{
"title": "2.3.1 可扩展的 GPU",
"page": 44
},
{
"title": "2.3.2 发展近况",
"page": 44
},
{
"title": "2.3.3 未来发展趋势",
"page": 45
}
]
},
{
"title": "参考文献与课外阅读",
"page": 45
}
]
}
]
}
需要转换为一种用制表符间隔的树状的格式
前言 2
目录 11
第 1 章 引言 16
1.1 异构并行计算 17
1.2 现代 GPU 的体系结构 21
1.3 为什么需要更高的速度和并行化 23
1.4 应用程序的加速 24
1.5 并行编程语言和模型 26
1.6 本书的总体目标 27
1.7 本书的组织结构 28
参考文献 31
第 2 章 GPU 计算的发展历程 34
2.1 图形流水线的发展 34
2.1.1 固定功能的图形流水线时代 35
2.1.2 可编程实时图形流水线的发展 38
2.1.3 图形与计算结合的处理器 40
2.2 GPGPU:一个中间步骤 42
2.3 GPU 计算 43
2.3.1 可扩展的 GPU 44
2.3.2 发展近况 44
2.3.3 未来发展趋势 45
参考文献与课外阅读 45
使用 jq 的递归函数,可以轻松处理这种嵌套的数据
jq -r '
def format($node; $indent):
("\t" * $indent) + "\($node.title)\t\($node.page)",
($node.kids[]? | format(.; $indent+1));
.bookmarks[] | format(.; 0)
' bookmarks.json > bookmarks.txt