SerenityOS json 命令实战指南:语法高亮、缩进美化与点分查询
【免费下载链接】serenityThe Serenity Operating System 🐞项目地址: https://gitcode.com/GitHub_Trending/se/serenity
json是 SerenityOS 自带的 JSON 命令行工具,核心能力是「美化打印」:把紧凑的 JSON 文本重新排版为带缩进和语法高亮的可读形式,并支持从标准输入读取、指定缩进宽度,以及用点分路径直接抽取嵌套数据。读完本文,你将掌握json的全部命令行用法,并理解其背后基于 AK 库 JSON 解析与序列化实现的工作机理,可直接在系统 shell 中处理伪文件系统输出与配置文件。
命令概览:用途、语法与输入方式
json用于对 JSON 文件进行 pretty-print(美化打印),并附带语法着色(syntax-coloring)与缩进。其手册页(Base/usr/share/man/man1/json.md)给出的基本语法为:
$ json [options...] [path...]两个关键设计点:
- 未提供
path参数时读取标准输入(stdin)。这使得json可以作为一个过滤式管道工具,直接承接其他程序产生的 JSON 输出。 - 提供
path时读取指定文件。从源码实现看(Userland/Utilities/json.cpp),它通过Core::File::open_file_or_standard_stream统一处理「文件或标准流」两种来源,逻辑上二者等价。
在 SerenityOS 中,许多系统接口以 JSON 形式暴露数据,例如/sys/kernel/processes伪文件即为进程列表的 JSON 描述,json是阅读这类数据的默认利器。
选项与参数详解
json的完整命令行接口由Core::ArgsParser解析(见 Userland/Utilities/json.cpp),源码中的选项定义比手册页更丰富,综合如下:
| 选项 | 长选项 | 含义 | 默认值 |
|---|---|---|---|
--help | — | 显示帮助信息并退出 | — |
-i | --indent-size | 每一级缩进的空格数 | 4 |
-q | --query | 点分查询键(dotted query key),抽取 JSON 中的子值 | 空(不查询) |
-R | —(源码中无长名) | 控制输出着色:always/never/auto | auto |
说明与细节:
-i, --indent-size:参数为整数,代表每级嵌套缩进的空格宽度。源码中默认值为u32 spaces_in_indent = 4(Userland/Utilities/json.cpp),即不指定时每级缩进 4 个空格。-q, --query:参数为形如foo.*.bar的点分路径。使用时工具会先解析完整 JSON,再按路径抽取目标子值并只打印该子值;路径段支持对象键名、数组数字下标和*通配符(详见下文「点分查询深入」)。-R(着色开关):这是源码中确认存在但手册页未列出的增强选项,取值为三选一:always:无条件输出 ANSI 颜色;never:禁用颜色;auto(默认):通过Core::System::isatty(STDOUT_FILENO)判断标准输出是否为终端,仅在终端中着色(Userland/Utilities/json.cpp)。管道/重定向到文件时自动关闭颜色,避免污染输出内容。- 传入非法值时,工具会向标准错误输出提示并返回退出码
1。
位置参数path:要美化打印的 JSON 文件路径,可选。源码中声明为Core::ArgsParser::Required::No(Userland/Utilities/json.cpp),印证了「缺省即读 stdin」的行为。
完整实战示例
手册页给出了 5 个可直接运行的核心示例,此处逐一展开:
# 1. 美化打印标准输入(管道) $ cat /sys/kernel/processes | json从 stdin 读入进程列表 JSON 并打印,此时 stdout 为终端,默认自动着色。
# 2. 美化打印一个文件 $ json json-data.json直接指定文件路径,效果等价于cat json-data.json | json。
# 3. 每级缩进 2 个空格 $ json -i 2 json-data.json-i 2将缩进宽度从默认的 4 改为 2,适合层级较深、需要横向压缩输出的场景。
# 4. 按点分路径查询文件中的子数据 $ json -q 1 .config/CommonLocations.json对.config/CommonLocations.json解析后,只抽取路径1(即数组下标为 1 的元素)并打印。注意这里路径1是数字段,对应数组索引访问。
# 5. 从管道查询进程列表中的某个字段 $ cat /sys/kernel/processes | json -q processes从 stdin 读取进程 JSON,抽取顶层键processes对应的值输出。
作为练习素材,仓库内自带真实的 JSON 文件 Base/home/anon/.config/bookmarks.json(浏览器书签),可实测各类查询:
# 完整美化打印书签文件 $ json .config/bookmarks.json # 只取第 1 个书签对象(数组下标 0) $ json -q 0 .config/bookmarks.json # 取所有书签的 url 字段(* 通配符) $ json -q '*.url' .config/bookmarks.json点分查询(-q)的语义与规则
查询功能由源码中的query函数实现(Userland/Utilities/json.cpp),其工作方式为:
- 先用
dotted_key.split_view('.')把查询串按.拆成键段序列(Userland/Utilities/json.cpp); - 从根值开始逐段向下递归:每一段作用于当前值后,把结果交给下一段;
- 当所有段处理完毕(
key_index == key_parts.size())时返回当前值。
各段的具体行为:
- 对象键名:若当前值是对象,调用
value.as_object().get(key)取对应成员,成员不存在时得到空值(value_or({}))。 - 数组下标:若当前值是数组,尝试把该段解析为整数
key.to_number<int>(),成功后用value.as_array().at(index)取对应元素(Userland/Utilities/json.cpp)。 *通配符:当段恰好为*时,对当前对象的所有成员值或数组的所有元素递归应用剩余路径,并把所有命中结果收集为一个新的JsonArray返回(Userland/Utilities/json.cpp)。这就是-q '*.url'能一次取出多个 url 的原因。
因此查询路径可以自由组合,例如processes.*.pid表示「processes 数组中每个元素的 pid 字段」,0.title表示「数组首元素的 title 字段」。
源码剖析:美化打印与语法高亮如何实现
美化与着色逻辑集中在print函数(Userland/Utilities/json.cpp),值得逐层拆解:
缩进生成:print_indent循环输出indent * spaces_per_indent个空格(Userland/Utilities/json.cpp),即当前嵌套深度乘以每级宽度。对象打印时每行成员前缩进indent + 1级,闭合}回到indent级,形成标准的层级缩进效果。
对象与数组的展开:对对象,先输出{,随后用object.for_each_member遍历每个键值对,键以"key":形式输出,成员之间用逗号分隔,最后一个成员不带逗号(依据printed_members < object.size()判断,Userland/Utilities/json.cpp);对数组同理,用array.for_each逐元素输出并用逗号分隔(Userland/Utilities/json.cpp)。整套逻辑由 AK 库的 JsonObject.h(for_each_member、get、size)与 JsonArray.h 提供支撑。
语法高亮配色:着色基于 ANSI 转义序列(Userland/Utilities/json.cpp),不同 JSON 类型对应不同颜色:
| JSON 类型 | ANSI 颜色码 | 视觉效果 |
|---|---|---|
| 对象键名 | \033[33;1m | 黄色(粗体) |
| 字符串 | \033[31;1m | 红色 |
| 数字 | \033[35;1m | 紫色 |
| 布尔值 | \033[32;1m | 绿色 |
| null | \033[34;1m | 蓝色 |
着色前通过is_string/is_number/is_bool/is_null判断类型,结束时统一以\033[0m复位。该设计使嵌套结构在终端中一眼可辨。
数据流与权限模型:serenity_main首先pledge("stdio rpath"),打开输入后降级为pledge("stdio")(Userland/Utilities/json.cpp读入全文,JsonValue::from_string(file_contents)完成解析——解析出错会通过TRY` 直接返回错误,因此输入不是合法 JSON 时工具会报错退出。
底层支撑:AK 的 JSON 解析与测试验证
json工具本身很薄,核心 JSON 能力全部来自 AK 库:
- 解析入口:
JsonValue::from_string实际委托给JsonParser(input).parse()(AK/JsonValue.cpp),由 JsonParser.h 实现语法分析。 - 值模型:
JsonValue内部用Variant表示六类值——空、布尔、i64、u64、double、字符串,以及独占指针持有的JsonArray/JsonObject(AK/JsonValue.cpp),因此能完整覆盖 JSON 规范中的全部类型。
仓库的单元测试 Tests/AK/TestJSON.cpp 为解析器的正确性提供了充分佐证,可帮助理解边界行为:
json_parse_rejects_excessive_nesting_depth与json_parse_accepts_reasonable_nesting_depth(Tests/AK/TestJSON.cpp):嵌套 4096 层被拒绝,64 层可接受,说明解析器设有嵌套深度上限以防御栈溢出。json_parse_fails_on_invalid_number(Tests/AK/TestJSON.cpp):-、00、01、.1、1e、0x1、+10等非法数字形式均被拒绝,且顶层不允许出现0,0这类带尾逗号的文本。json_parse_special_numbers(Tests/AK/TestJSON.cpp):-0、0e1000、1e-2000等特殊浮点写法按 double 位级比对。json_64_bit_value_coerced_to_32_bit(Tests/AK/TestJSON.cpp):验证i64/u64极大极小值的解析与按位宽查询(is_integer<T>)行为。json_duplicate_keys(Tests/AK/TestJSON.cpp):重复键后写覆盖先写,序列化结果为{"test":"baz"}。
这些测试与 Tests/AK/TestJSON.cpp 中的load_form、json_utf8_character、json_encoded_surrogates(含 emoji 代理对处理)等用例共同表明:json命令能正确处理 UTF-8 字符串、64 位整数和深层结构,而不仅是玩具级的 pretty-printer。
在 SerenityOS 中的典型工作流
综合以上用法,json在系统中的典型场景可归纳为三类:
- 阅读系统 JSON 接口:
/sys/kernel/processes等伪文件以 JSON 输出系统状态,cat ... | json是最直接的格式化阅读方式;配合-q processes可只关注核心字段,避免长输出淹没视线。 - 检查用户配置文件:系统与应用的 JSON 配置(如书签文件 Base/home/anon/.config/bookmarks.json)紧凑存放,
json <file>即可获得带颜色的可读视图。 - 作为管道过滤器:任何产生 JSON 的程序输出都可以接到
json上;配合-i 2调整缩进、-R always强制着色,可适配不同的消费端(终端、日志、脚本)。
手册页 Base/usr/share/man/man1/json.md 是了解该命令的第一手资料,本文所涉的源码与测试则提供了从接口到实现的完整闭环:命令层负责参数解析与输入输出,AK 库负责解析、类型模型与遍历 API,测试保障解析器在数字格式、编码与深度上的严格性。
【免费下载链接】serenityThe Serenity Operating System 🐞项目地址: https://gitcode.com/GitHub_Trending/se/serenity
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考