- 开发工具
【免费下载链接】jc
CLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.
本文聚焦于 jc 项目中的systemctl_lj解析器,它专门用于将 Linux 上systemctl list-jobs命令输出的 systemd 任务队列文本转换为结构化 JSON 数据。读完本文,你将掌握systemctl_lj的 CLI 与 Python 模块两种调用方式、完整的输出 Schema 与类型转换规则、解析器对真实输出(包括空数据与结尾统计行)的容错处理原理,以及如何结合仓库中的测试夹具进行验证。
什么是systemctl_lj解析器
systemctl list-jobs是 systemd 提供的用于查看当前待执行与正在执行的任务(job)队列的命令,它会列出任务编号(JOB)、目标单元(UNIT)、任务类型(TYPE,如 start/stop/restart)以及任务状态(STATE,如 waiting/running)。默认输出是面向终端阅读的文本表格:
JOB UNIT TYPE STATE 3543 nginxAfterGlusterfs.service start waiting 3545 glusterReadyForLocalhostMount.service start running 3506 nginx.service start waiting 4 jobs listed.这种表格格式适合人眼观察,却难以直接交给脚本与自动化工具处理。jc 项目中的systemctl_lj解析器(源文件位于 jc/parsers/systemctl_lj.py)正是为了解决这个问题而存在:它读取systemctl list-jobs的文本输出,将其转换为由字典组成的列表,每个字典对应一个任务,包含job、unit、type、state四个字段,从而让输出可以无缝衔接jq等 JSON 处理工具,简化系统管理自动化脚本。
从解析器元数据(info类)可以看到其定位:版本 1.7,作者 Kelly Brazil,compatible = ['linux'](仅面向 Linux 平台),magic_commands = ['systemctl list-jobs']表示 jc 可以在 CLI 中直接识别并匹配该命令的输出,tags = ['command']归类为命令输出解析器。
CLI 用法:两种调用方式
方式一:管道输入
将systemctl list-jobs的输出通过管道交给 jc,并指定--systemctl-lj解析器:
systemctl list-jobs | jc --systemctl-lj方式二:jc 直接包装命令
利用解析器的magic_commands能力,让 jc 直接运行命令并解析输出:
jc systemctl list-jobs两条命令的效果等价。man 手册(man/jc.1)中也登记了--systemctl-lj这一 CLI 选项,shell 补全脚本(completions/jc_bash_completion.sh、completions/jc_zsh_completion.sh)同样包含对该选项的补全支持。
常用输出修饰参数
与 jc 所有命令解析器一致,systemctl_lj支持两个重要的输出修饰开关:
-p(pretty):以缩进美化格式输出 JSON,便于阅读;-r(raw):跳过类型转换,直接输出"未处理"的原始字符串字段(详见下文 Schema 章节)。
组合使用示例:
systemctl list-jobs | jc --systemctl-lj -p systemctl list-jobs | jc --systemctl-lj -p -rPython 模块用法
除了命令行,systemctl_lj同样可以作为 Python 库函数使用。解析器名称是systemctl_lj,对应模块jc.parsers.systemctl_lj,核心入口为parse(data, raw=False, quiet=False)函数:
import jc # 假设 systemctl_lj_command_output 为 systemctl list-jobs 的文本输出 result = jc.parse('systemctl_lj', systemctl_lj_command_output)函数签名与参数含义(与文档及源码实现一致):
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
data | string | 无 | 待解析的文本数据 |
raw | boolean | False | 为True时返回未转换类型的原始结构数据 |
quiet | boolean | False | 为True时抑制警告信息(如平台兼容性警告) |
返回值恒为"字典列表"(List of Dictionaries),具体形态取决于raw取值:
raw=False(默认):经过类型转换、符合 Schema 的处理后数据;raw=True:与文本一一对应的原始字符串字段。
在解析入口处,源码先调用jc.utils.compatibility(__name__, info.compatible, quiet)检查平台兼容性(非 Linux 平台且未指定quiet时会给出警告),再通过jc.utils.input_type_check(data)校验输入类型,最后调用jc.utils.has_data(data)判断是否存在可解析的数据——这些前置检查共同保证了解析器在异常输入下也能安全返回。
输出 Schema 详解
文档中定义的systemctl_lj输出 Schema 如下:
[ { "job": integer, "unit": string, "type": string, "state": string } ]各字段与systemctl list-jobs输出列的对应关系及类型转换规则:
| 字段 | 对应列 | 处理后类型 | 说明 |
|---|---|---|---|
job | JOB | integer | 任务编号,由字符串经convert_to_int转换为整数 |
unit | UNIT | string | 任务作用的 systemd 单元名,如nginx.service |
type | TYPE | string | 任务类型,如start、stop、restart、reload等 |
state | STATE | string | 任务状态,如waiting(排队等待)、running(执行中) |
字段名的映射方式非常直接:解析器取文本输出的首行作为表头(转为小写后按空白拆分),再用dict(zip(header_list, entry_list))将表头与每一行数据逐一配对。这意味着如果未来 systemd 改变列顺序或增加列,解析器仍能按新表头自适应生成字段。
类型转换细节:raw 与 processed 的差异
_process()函数是类型转换的关键实现(见 jc/parsers/systemctl_lj.py):
def _process(proc_data): int_list = {'job'} for entry in proc_data: for key in entry: if key in int_list: entry[key] = jc.utils.convert_to_int(entry[key]) return proc_data它仅将job字段从字符串转换为整数,其余字段保持字符串。因此:
- 默认输出中,
job是无引号的整数(如3543); - 使用
-r(raw)时,job保留原始字符串形式(如"3543"),便于保留原始文本的逐字段快照。
这与文档给出的两组示例完全吻合。
真实示例:从文本到 JSON
文档示例取自 Ubuntu 18.04 的真实系统,仓库测试夹具(tests/fixtures/ubuntu-18.04/systemctl-lj.out)中保存了对应的原始输入:
JOB UNIT TYPE STATE 3543 nginxAfterGlusterfs.service start waiting 3545 glusterReadyForLocalhostMount.service start running 3506 nginx.service start waiting 4 jobs listed.默认(processed)输出
systemctl list-jobs | jc --systemctl-lj -p[ { "job": 3543, "unit": "nginxAfterGlusterfs.service", "type": "start", "state": "waiting" }, { "job": 3545, "unit": "glusterReadyForLocalhostMount.service", "type": "start", "state": "running" }, { "job": 3506, "unit": "nginx.service", "type": "start", "state": "waiting" } ]raw 输出
systemctl list-jobs | jc --systemctl-lj -p -r[ { "job": "3543", "unit": "nginxAfterGlusterfs.service", "type": "start", "state": "waiting" }, { "job": "3545", "unit": "glusterReadyForLocalhostMount.service", "type": "start", "state": "running" }, { "job": "3506", "unit": "nginx.service", "type": "start", "state": "waiting" } ]EXAMPLES 速查文档(EXAMPLES.md)中也收录了同样的用例,并给出了等价写法jc -p systemctl list-jobs,可作为日常速查参考。
解析器源码原理:逐行拆解
深入 jc/parsers/systemctl_lj.py 的parse()主逻辑,其处理流程可以归纳为四个阶段:
- 前置校验:依次执行平台兼容性检查(
jc.utils.compatibility)、输入类型检查(jc.utils.input_type_check)。 - 清理输入:用
list(filter(None, data.splitlines()))剔除所有空行;随后对每一行执行非 ASCII 字符清洗——entry.encode('ascii', errors='ignore').decode(),将可能的乱码或特殊字符安全剥离,避免污染后续解析。 - 提取表头:取清理后的第一行,转为小写并按空白
split()成表头字段列表,作为后续字典的键。 - 逐行解析:遍历剩余行。遇到包含
'No jobs running.'或'jobs listed.'的行立即终止循环——这正是 systemd 在任务队列为空(No jobs running.)或队列末尾(N jobs listed.)时的输出特征;否则以entry.split(maxsplit=4)拆分当前行(限制最大拆分次数为 4,保证 UNIT 列即使包含空格也不会被错误拆开),与表头配对生成字典并追加到结果列表。
最终,若raw=True直接返回原始字典列表,否则交给_process()完成job字段的整数转换后返回。
边界情况:空数据与空队列
对于完全没有数据的情况,parse('', quiet=True)会返回空列表[]——这一点由单元测试显式覆盖(见下文测试章节)。而对于"有数据但队列为空"的情况(输出只有No jobs running.及统计行),解析逻辑同样会在命中结束标记时停止,不会产生虚假的任务条目。
测试与验证:仓库如何保证正确性
systemctl_lj的正确性由单元测试(tests/test_systemctl_lj.py)保障,测试覆盖了两个场景:
test_systemctl_lj_nodata:调用jc.parsers.systemctl_lj.parse('', quiet=True)断言返回[],验证空输入安全;test_systemctl_lj_ubuntu_18_4:读取 Ubuntu 18.04 真实夹具输出 tests/fixtures/ubuntu-18.04/systemctl-lj.out,断言解析结果与预期 JSON tests/fixtures/ubuntu-18.04/systemctl-lj.json 完全一致。
其中预期的 JSON 内容为:
[{"job": 3543, "unit": "nginxAfterGlusterfs.service", "type": "start", "state": "waiting"}, {"job": 3545, "unit": "glusterReadyForLocalhostMount.service", "type": "start", "state": "running"}, {"job": 3506, "unit": "nginx.service", "type": "start", "state": "waiting"}]可以看到job字段在预期输出中已经是整数类型,与_process()的类型转换行为一一对应。如果你需要在本地复现验证,可以运行项目根目录的测试脚本(如runtests.sh),或直接执行:
python -m unittest tests.test_systemctl_lj解析器元信息与兼容性说明
根据 docs/parsers/systemctl_lj.md 与源码info类的记录:
- 版本:1.7
- 作者:Kelly Brazil(kellyjonbrazil@gmail.com)
- 兼容平台:仅 Linux(
compatible = ['linux']),在非 Linux 平台调用时 jc 会输出兼容性警告,除非传入quiet=True - 输入来源:
systemctl list-jobs命令标准输出 - 输出形态:List of Dictionaries(原始或处理后的结构化数据)
需要注意的是,本文所述行为均以当前仓库 jc/parsers/systemctl_lj.py 的实现为准;由于解析器依赖systemctl list-jobs首行表头与固定统计行格式,若 systemd 未来大幅调整输出格式,解析结果可能随之变化。在使用时,请确保运行环境为 Linux 且 systemd 输出保持默认的列式文本布局(不带--no-legend等改变表头或统计行的参数)。
结语:让 systemd 任务队列进入自动化流水线
systemctl_lj解析器为系统管理员与运维脚本提供了一条从 systemd 任务队列到 JSON 的直通路径:既可以在 shell 中用systemctl list-jobs | jc --systemctl-lj即时获得结构化数据,也可以在 Python 中通过jc.parse('systemctl_lj', ...)深度集成。配合-r开关保留原始字符串、quiet抑制告警、以及仓库中配套的测试夹具与速查示例,你可以放心地将任务队列监控、批量服务启停编排等场景交给这一解析器,再交由jq或 Python 程序进一步加工。
- 开发工具
【免费下载链接】jc
CLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.
相关推荐
OpenProject 如何按版本规划产品路线图(Roadmap)?
OpenProject 如何按版本规划产品路线图(Roadmap)? OpenProject 的 Roadmap 是一个按版本(Version)汇总工作包(Wo
开发工具jc 解析器实战:使用 jc --gpg 将 gpg --with-colons 输出转换为 JSON
jc 解析器实战:使用 jc gpg 将 gpg with colons 输出转换为 JSON 导读 本文介绍 jc(JSON Convert)项目中的 gpg
开发工具jc 解析器实战:使用 jc --sfdisk 将 sfdisk 分区表输出转换为 JSON
jc 解析器实战:使用 jc sfdisk 将 sfdisk 分区表输出转换为 JSON 导读 jc 是一个把常用命令行工具输出、文件类型和通用字符串转换为 J
开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考