jq map函数是否修改输入对象?为何后续数组求和操作报错?
jq中map后求和报错的原因分析
你的问题核心是jq上下文的变化,以及命令优先级/括号使用的问题:
1. 单独执行命令正常的原因
你单独执行[.[].cpus.total]|add时,jq的当前上下文是原始的输入数组,所以.[].cpus.total可以正常遍历数组里的每个对象,提取cpus.total并求和,完全没问题。
2. 错误命令的问题所在
你提到的错误命令:
cat /tmp/o.json | jq -c '[(map(.cpus.total - .cpus.allocated) | add), "/", [.[].cpus.total]|add]'
如果输入是顶级数组,理论上这个命令应该能正常运行,但你出现Cannot iterate over number (2556)的错误,说明执行[.[].cpus.total]时,当前上下文变成了数字2556(也就是map(...) | add的结果)。
这大概率是因为你实际输入的命令括号位置错误,比如写成了:
# 错误的括号位置:map后直接管道到数组构造器 cat /tmp/o.json | jq -c 'map(.cpus.total - .cpus.allocated) | [add, "/", [.[].cpus.total]|add]'
这种情况下,map把原始数组转换成差值数组,管道|将上下文切换成这个差值数组;接着add把差值数组求和成数字2556,此时数组构造器[add, "/", ...]里的所有表达式的上下文都是2556。第三个表达式[.[].cpus.total]试图遍历数字2556,自然触发报错。
3. 为什么添加额外数组包裹能运行
你写的正确命令:
cat /tmp/o.json | jq -c '[(map(.cpus.total - .cpus.allocated) | add), "/", [[.[].cpus.total]|add][0] ]'
这里的关键是外层的[]把三个表达式都限定在原始输入的上下文中:
- 第一个表达式
(map(...) | add)基于原始数组计算差值总和; - 第三个表达式
[[.[].cpus.total]|add][0]里的.还是原始数组,所以[.[].cpus.total]|add能正常求和得到2764,[...][0]只是把结果从数组里取出来——其实这个额外包裹是多余的,你直接写[.[].cpus.total]|add也应该能运行,除非你的命令括号确实写错了。
推荐的正确写法
为了避免上下文混淆,更清晰的写法是用变量保存原始输入的总和:
cat /tmp/o.json | jq -c ' # 保存原始数组的总CPU数到变量$total ([.[].cpus.total] | add) as $total # 构造结果数组 | [(map(.cpus.total - .cpus.allocated) | add), "/", $total] '
这种写法完全隔离了两个计算步骤,不会出现上下文混淆的问题。
内容的提问来源于stack exchange,提问作者Chip Seraphine
相关产品推荐
相关产品推荐

