关于 jo
这项面向 Shell 的技能介绍如何用 `jo` 构造 JSON,避免手动处理引号。内容涵盖类型判断、嵌套结构、数组、文件输入和常见命令行用法,并建议对复杂语法查阅手册。
主要功能
- 01用 Shell 值构造 JSON
- 02推断或强制 JSON 值类型
- 03组合嵌套对象和数组
- 04读取并嵌入文件内容
- 05更新现有 JSON 文档
- 06curl 和 kubectl 示例
适用场景
- 01用 Shell 变量构造 API 请求体
- 02在脚本中生成嵌套 JSON
- 03通过命令行修改 Kubernetes 资源
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ petr-korobeinikov/ skills --skill jo安装后在 Claude Code 中输入/jo确认已加载。
附带文件references/options.md
详细介绍
jo
在 Shell 片段中使用 jo 构建 JSON,
而不是手动输入带引号的 JSON 字面量。
jo 会在内部处理 JSON 引号,
因此 Shell 变量可以顺畅展开,
你也不必费心处理嵌套的单引号和双引号。
权威文档:
https://github.com/jpmens/jo
(README 和 jo.md 手册页)。
依赖任何非简单用法前,请先对照手册确认。
为什么
- 在 Shell 字符串中手写 JSON,很容易陷入引号转义的泥潭。
在
'{"user":"x"}'中插入$VAR,要么会破坏单引号, 要么就得使用难以阅读且容易输错的'"$VAR"'模式。 - 内嵌 JSON 中的拼写错误(缺少逗号、多余引号、尾随逗号) 会在服务端报错, 而不是在解析时就报错 — 在很长的单行负载中很难发现。
jo会根据值推断类型: 数字、布尔值、null、嵌套对象和数组都会自动识别; 如果推断结果不符合预期,可按单词使用-s/-n/-b覆盖 (例如必须保留为字符串的数字 ID)。jo支持组合使用: Shell 变量、命令替换、方括号路径简写 和嵌套的jo调用都能使用,无需重新转义。
jo 如何判断值的类型
根据手册页,值的处理流程如下:
- 尝试将值解析为 JSON。
5→ 数字,true/false→ 布尔值,null→ null,{...}/[...]→ 嵌入的对象/数组, 看起来像数字但不是有效浮点数的字符串 (例如3.14159.26)→ 字符串。 - 如果 JSON 解析失败,
检查特殊值前缀:
@file、%file、:file(见下文的从文件读取)。 - 否则,将其视为字面字符串。
缺失/空值(k=)会变成 null。
传入 -B 可禁用对字面字符串 true/false/null 的检测。
全局使用时,
-n 会丢弃值为空的键
(不要与 -- 后按单词使用的 -n 强制转换混淆)。
直接替换
| 不要 | 请使用 |
|---|---|
'{"name":"alice"}' | "$(jo name=alice)" |
'{"name":"'"$USER"'"}' | "$(jo name="$USER")" |
'{"count":5,"active":true}' | "$(jo count=5 active=true)" |
'{"value":null}' | "$(jo value=null)"(或 "$(jo value=)") |
'{"tags":["a","b","c"]}' | "$(jo tags="$(jo -a a b c)")" |
'{"point":[1,2]}' | "$(jo 'point[]=1' 'point[]=2')" |
'{"geo":{"lat":10,"lon":20}}' | "$(jo 'geo[lat]=10' 'geo[lon]=20')" |
'{"user":{"id":1,"name":"alice"}}' | "$(jo user="$(jo id=1 name=alice)")" |
'{"code":"12345"}'(字符串 ID) | "$(jo -- -s code=12345)" |
方括号路径形式(key[]=、key[sub]=)仅支持一级嵌套 —
'a[b][c]=1' 会静默丢弃 [c],并生成 {"a":{"b":1}}。
如需更深层嵌套,
请通过命令替换使用嵌套的 jo。
语法速查
值的形式
k=v— 先按 JSON 解析,再检查前缀,最后作为字面字符串处理 (见*jo如何判断值的类型*)。k@v— 根据真值生成布尔值 (T/t或非零数字 →true,否则为false); 适用于flag@$ENABLED。k=@file— 将file的内容作为字符串值加载。k=%file— 将file作为 Base64 编码字符串加载。k=:file— 将file解析为 JSON 并嵌入。k:=file或k:=-— 与k=:file相同,但作为运算符使用;-表示从标准输入读取 JSON。
如需在字符串值开头使用字面字符 @、% 或 :,
请用 \ 转义:
twitter='\@jpmens'、
vimcmd='\:split'、
uri='\\%20'。
方括号路径(一级)
'name[]=v1' 'name[]=v2'— 追加到name数组。'obj[k]=v'— 创建{"obj":{"k":v}}。- 结合
-d.(路径分隔符)使用点号表示法:jo -d. geo.lat=10 geo.lon=20等同于jo 'geo[lat]=10' 'geo[lon]=20'。 - 方括号形式务必加引号 —
未加引号的
[/]会被 zsh 的通配符匹配捕获 (bash 也一样, 只要有任何匹配项)。
数组
jo -a v1 v2 v3— 自动推断类型的值组成的数组。jo -a -- -s 123 hello -n "five"— 在数组内逐词进行类型转换 (此处为:["123","hello",4]— 对非数字字符串使用-n会返回其长度)。
类型转换
jo -- -s k=v— 强制转换为字符串。 适用于数字 ID、版本字符串、电话号码和邮政编码。jo -- -n k=v— 强制转换为数字 (非数字字符串会转换为其长度)。jo -- -b k=v— 强制转换为布尔值 (空值 →false,其他任何值 →true)。- 只要列表中的第一个词以
-开头, 就必须在词列表前加上--; 为与手册保持一致,请始终传入它。
全局选项
最常用的两个:
-p— 美化输出 (生产环境的请求载荷中应省略)。-a— 输出数组而非对象。
完整选项列表
(-B、-D、-n 全局选项、-d sep、-f file、-e、-o、-v/-V,
以及 -- 后逐词类型转换的语义)
请参阅 references/options.md。
惯用写法
使用 curl 发送带请求体的 POST:
curl -X POST https://api.example.com/v1/users \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$(jo name="$NAME" email="$EMAIL" active=true)"
用于一级嵌套的方括号简写
(无需嵌套 jo 命令替换):
curl -X POST https://api.example.com/v1/orders \
-H "Authorization: Bearer $TOKEN" \
-d "$(jo \
'customer[id]='"$CUSTOMER_ID" \
'customer[name]='"$CUSTOMER_NAME" \
'items[]='"$SKU_A" \
'items[]='"$SKU_B")"
嵌套深度超过一级 — 通过命令替换构建 (或存入变量):
payload=$(jo \
name="$NAME" \
address="$(jo street="$STREET" city="$CITY")" \
tags="$(jo -a admin user)")
curl -X POST -d "$payload" https://api.example.com/v1/users
kubectl 补丁:
kubectl patch deployment web \
--type=merge \
--patch "$(jo spec="$(jo replicas=3)")"
必须保持为字符串的数字 ID
(否则 jo 会将 "id":12345 输出为数字):
curl -X POST -d "$(jo -- -s id=12345 name="$NAME")" \
https://api.example.com/v1/users
修改现有的 JSON 文档:
curl -sSL https://api.example.com/v1/config \
| jo -f - updated_at="$(date -Iseconds)" version="$NEW_VERSION"
不应使用 jo 的情况
大型固定 JSON 文档
与一长串 jo 调用相比,使用包含 JSON 字面量的 heredoc 更清晰,
而且可以直接从 API 文档复制 JSON,无需转换:
curl -X POST -d @- https://api.example.com/v1/config <<'JSON'
{
"feature_flags": {
"alpha": true,
"beta": false
},
"limits": {
"rps": 100,
"burst": 200
}
}
JSON
主机上没有 jo
某些精简的 CI 镜像或受限服务器没有安装它。 请改用 heredoc; 不要退而使用脆弱的行内带引号 JSON。
安装 jo
- macOS:
brew install jo或sudo port install jo - Debian/Ubuntu:
apt install jo - Fedora:
dnf install jo - Alpine:
apk add jo - Gentoo:
emerge jo - Arch:
pacman -S jo(位于extra) - Snap:
snap install jo - Windows:
scoop install jo - Docker:
docker run --rm jpmens/jo ... - 从源代码安装:https://github.com/jpmens/jo
jo 不在 aqua/mise 默认的短名称注册表中;
在由 mise 管理的主机上,请通过包管理器安装,
或使用 ubi:jpmens/jo。
适用范围
适用于任何通过 shell 代码片段输出 JSON 的场景:
Bash工具调用。SKILL.md/README.md/ 文档中的代码片段。scripts/下的脚本。- Makefile 配方。
- CI 配置。
- API 冒烟测试说明。
如果你在编辑文件时发现手写的行内 JSON 字符串,
请在同一次编辑中将其替换为等效的 jo 写法。