如何用jq验证符合Shell变量命名等规则的JSON文件?
使用JQ验证JSON并转换为Bash兼容格式
问题
我正在编写一个bash库,需要读取包含用户输入的JSON文件;该JSON不会被篡改,但可能包含对bash脚本有害的值,具体取决于上游表单的验证情况。
在将JSON加载到bash数组的函数中,我尚不清楚必须存在哪些键,但仍需强制执行以下规则:
- JSON必须包含单个对象
- 所有键需符合Shell变量命名规范
- 所有值必须是标量
- 值中不能包含NUL字节
示例JSON
错误示例
{ "": "empty key shall fail", "illegal key shall fail": "keys shall follow the naming convention of shell variables", "non_scalar_shall_fail_1": [1,2], "non_scalar_shall_fail_2": {"k":"v"}, "nul_byte_shall_fail": "file.php\u0000.txt" }
合法示例
{ "task_uuid": "5d7ea654-b649-452b-a8fd-002b56be9a59", "task_name": "hello world", "user_email": null, "min": 7, "max": 100, "ave": 2.5, "file_in": "data.txt", "file_out": "results.txt" }
现有脚本与问题
我已能强制执行部分规则,但不知道如何实现单个对象验证和标量值验证,现有jq脚本如下:
jq -r ' to_entries[] | if (.key | test("\\A[_a-zA-Z]\\w*\\z") | not) then ("error: illegal key " + (.key | tojson) + "\n" | halt_error(1)) else if (.value | tostring | test("\u0000")) then ("error: NUL byte in value " + (.value | tojson) + "\n" | halt_error(1)) else # dummy output .key + "=" + (.value | @sh) end end '
执行后出现异常:halt_error仅拦截部分错误,还触发了核心转储:
error: illegal key "" task_uuid='5d7ea654-b649-452b-a8fd-002b56be9a59' task_name='hello world' user_email=null min=7 max=100 ave=2.5 file_in='data.txt' file_out='results.txt' *** Error in `jq': corrupted double-linked list *** ... Aborted (core dumped)
请问是否可以用jq完成所有这些验证,还是需要更换其他工具?
解决方法
完全可以用jq完成所有规则验证,核心转储是因为遍历逻辑导致jq在触发错误后仍继续处理后续输入,损坏了内部状态。以下是覆盖所有规则的修复脚本:
完整验证脚本
jq -r ' # 验证规则1:输入必须是单个JSON对象 if type != "object" then ("error: input must be a single JSON object\n" | halt_error(1)) end # 遍历键值对,验证剩余规则并输出结果 | to_entries[] | ( # 验证规则2:键符合Shell变量命名规范 if .key | test("\\A[_a-zA-Z]\\w*\\z") | not then ("error: illegal key " + (.key | tojson) + "\n" | halt_error(1)) end # 验证规则3:值为标量类型(null/布尔/数字/字符串) | if .value | type | IN("null", "boolean", "number", "string") | not then ("error: non-scalar value for key " + (.key | tojson) + "\n" | halt_error(1)) end # 验证规则4:字符串值不含NUL字节(其他标量无需检查) | if .value | type == "string" and (.value | test("\u0000")) then ("error: NUL byte in value for key " + (.key | tojson) + "\n" | halt_error(1)) end # 输出bash兼容的键值对格式 | .key + "=" + (.value | @sh) ) '
关键改进说明
- 规则1实现:首先检查输入类型是否为
object,直接拦截数组、多个对象、原始值等非法输入。 - 规则3实现:通过
type | IN(...)判断值是否为标量,数组和对象类型会被立即报错终止。 - 修复核心转储:将所有逻辑整合到单个管道中,确保
halt_error触发后立即终止整个jq进程,不会继续处理后续输入条目或对象。 - 性能优化:仅对字符串类型检查NUL字节,其他标量类型无NUL风险,无需额外检查。
使用方式
- 将脚本内联到bash函数或保存为独立文件
- 执行验证:
jq -r '<脚本内容>' input.json - 验证通过时输出可直接导入bash的键值对,例如:
source <(jq -r '<脚本内容>' input.json) - 验证失败时输出错误信息并返回非零退出码,可被bash脚本捕获判断
内容的提问来源于stack exchange,提问作者Fravadona
相关产品推荐
相关产品推荐

