jc 本机实测:把 ps/df/ip/ls 输出变成 JSON,jq 一行查询,代价是慢 7 倍

4 阅读2分钟

jc 本机实测:把 ps/df/ip/ls 输出变成 JSON,jq 一行查询,代价是慢 7 倍

写运维脚本最烦的是解析命令输出:ps aux | awk '$3>0'、ls -l | awk '{print $9}',列一错位就全错。GitHub 上的 kellyjonbrazil/jc 思路很直接:把常见命令的文本输出转成 JSON,再交给 jq 按字段名取值。这篇在本机 Linux 上实际跑了 ps、df、ip route、ls -l 等,和 awk 写法比了正确性和耗时,坑也一并记下。

本机实测 + AI 辅助整理。测量时间:2026-11-01(Asia/Shanghai)。原始输出见文末说明。


本机环境

OS:  Linux x86_64
jc:  1.26.2(Python 3.10.22)
jq:  1.7

安装 jc

uv venv v && uv pip install --python v/bin/python jc   # 上一篇的 uv,装好不到 1 秒
export PATH=$PWD/v/bin:$PATH
jc --version

也可以 pip install jc、brew install jc,或直接下官方二进制。


实测 1:ps —— 内存占用前三的进程

ps aux | jc --ps | jq -r 'sort_by(-.mem_percent)|.[:3][]|"\(.pid) \(.mem_percent) \(.command[:40])"'

jc 已把 %MEM 转成数字字段 mem_percent,排序不用再 sort -k4 -nr 数第几列。

实测 2:df —— 只看使用率字段

df | jc --df | jq -c '.[]|select(.use_percent>=1)|{filesystem,use_percent,mounted_on}'
# {"filesystem":"/dev/vdb","use_percent":12,"mounted_on":"/"}

use_percent 是整数 12,不是字符串 "12%",比较时不用先去掉百分号。

实测 3:ip route / 地址计算

ip route | jc --ip-route | jq -c '.[]|{ip,via,dev}'
# {"ip":"default","via":"172.30.0.1","dev":"enp0s3"}
# {"ip":"172.17.0.0/16","via":null,"dev":"docker0"}
# {"ip":"172.30.0.0/24","via":null,"dev":"enp0s3"}

jc --ip-address <<< "172.30.0.2/24" | jq -c '{network,broadcast,hosts}'
# {"network":"172.30.0.0","broadcast":"172.30.0.255","hosts":254}

没有网关的路由 via 是 null,脚本里判断很干净。--ip-address 顺手当子网计算器用。

实测 4:ls -l —— 文件名带空格时 awk 翻车

touch "t/a b.txt"
ls -l t | jc --ls | jq -r '.[].filename'   # a b.txt
ls -l t | awk 'NR>1{print $9}'             # a      ← 被空格截断

这是本次最有说服力的一条:按列切分的 awk 天然处理不了带空格的文件名,jc 正确。
找 /usr/bin 下大于 10MB 的文件,两种写法结果一致(都是 3 个:cargo、rustdoc、x86_64-linux-gnu-lto-dump-14):

ls -l /usr/bin | jc --ls | jq '[.[]|select(.size>10000000)]|length'   # 3
ls -l /usr/bin | awk '$5>10000000' | wc -l                            # 3

实测 5:耗时对比

同一件事“统计 CPU 占用 >0 的进程数”,各循环 50 次:

写法50 次总耗时单次约
ps aux | jc --ps | jq ...3.387 s68 ms
ps aux | awk 'NR>1 && $3>0' | wc -l0.452 s9 ms

jc 慢约 7.5 倍,原因是每次都要启动 Python 解释器(空输入跑一次 jc --ps 就要 0.108 s)。交互用、cron 脚本里无所谓;在紧循环里调几千次就别用了。

彩蛋:magic 语法

jc -p uptime
# {"time":"21:16:20","uptime":"5:30","users":0,"load_1m":8.54, ...}

jc 命令 直接帮你执行并解析,省掉管道。


踩坑记录

  1. --ip-address 不是解析 ip addr 的。我把 ip addr 管给它直接报 could not parse;它解析的是单个 IP/CIDR 字符串。ip route 用 --ip-route。
  2. dig / ifconfig 本机没装,jc 有 --dig、--ifconfig 解析器但前提是命令本身存在;精简镜像里得先装 dnsutils / net-tools(我这台没有 sudo,这两项没测成,不贴编造的结果)。
  3. 启动开销固定 ~0.1 s,见实测 5。
  4. 解析失败会提示设 LC_ALL=C:中文 locale 下部分命令输出带中文,jc 可能不认。
  5. uv venv 默认不带 pip,所以 jc --pip-list 要配合 uv pip list 用(本机解析出 4 个包)。

结论

项目结果
带空格文件名jc 正确,awk $9 截断
字段类型百分比、大小自动转数字,null 显式
耗时50 次 3.387 s vs awk 0.452 s(≈7.5×慢)
单次启动约 0.108 s

一句话:jc 换来的是正确性和可读性,代价是 Python 启动时间。写给人看、要长期维护的脚本用 jc + jq;一次性、高频调用的还是 awk。

完整的测量脚本和进阶踩坑表以后会整理上架 Gumroad,先关注专栏「GitHub实测笔记」。
上一篇:uv 本机实测(装 33 个包,pip 9.8 秒 vs uv 0.9 秒)。
下一篇预告:BurntSushi/ripgrep——和 grep 在大目录里比搜索速度。有问题评论区见,看到都会回。