如何将jq中的对象序列合并为一个对象?

92

我想转换对象流:

{
  "a": "green",
  "b": "white"
}
{
  "a": "red",
  "c": "purple"
}

合并为一个对象:

{
  "a": "red",
  "b": "white",
  "c": "purple"
}

另外,我如何将相同的序列包装成一个数组?

[
    {
      "a": "green",
      "b": "white"
    },
    {
      "a": "red",
      "c": "purple"
    }
]

很遗憾,该手册的全面性严重不足,而通过谷歌搜索也找不到答案。


5
你是如何得到这个输入的?这个序列是通过 jq 命令创建并经过类似 .[] 过滤后生成的吗?还是它真的是你获得的原始输入状态?如果是前者,那么当使用有效的 JSON 时,导致序列产生的 jq 命令可能很容易修改为通过在迭代处理命令周围添加 [ 和 ] 来输出数组,而无需将两个 jq 命令连接起来,第二个 jq 命令将使用 -s。 - mwag
4个回答

135

如果您的输入是一系列对象,则除非jq有 inputs,否则必须通过将它们"合并",例如使用-s命令行选项来将它们组合起来。

因此,将对象组合在输入流中的一种方法是使用:

jq -s add

对于第二个问题,创建一个数组:

jq -s .

当然还有其他选择,但这些选择很简单,不需要最新版本的 jq。使用 jq 1.5及更高版本,您可以使用'inputs',例如 jq -n '[inputs]'

高效的解决方案

对于第一个问题(reduction),与其通过-s选项或使用[inputs]进行 slurping,不如使用reduce与inputs以及-n命令行选项更为高效。例如,将对象流合并为单个对象:

jq -n 'reduce inputs as $in (null; . + $in)'

同样地,不使用--null-input

jq 'reduce inputs as $in (.; . + $in)

19
@JenniferM. 你可以选择接受答案,而不是留下“感谢”评论。接受答案 - rene
1
当序列作为表达式的结果出现时怎么办?因为 <jq expression> | add 并不能完全满足我的需求。 - Kaos
5
好的,我只是需要发布这个来弄清楚如何做。我把我的 .[] | <expression> | add 改成了 . | map(<expression>) | add,现在它做到了我想要的 ;) - Kaos

41

使用命令行选项-s代替 slurping 的另一种方法是使用 inputs 过滤器。如下所示:

jq -n '[inputs] | add'

这将产生一个包含所有输入对象的组合的对象。


9
如果您通过 jq 过滤器而非外部输入到达此点,则建议将您的 jq 过滤器包装在 [] 中,可以参考 mwag 的评论
示例:
$ echo '[{"foo":42},{"foo":43}]' | jq '.[]'
{
  "foo": 42
}
{
  "foo": 43
}
$ echo '[{"foo":42},{"foo":43}]' | jq '[.[]]'
[
  {
    "foo": 42
  },
  {
    "foo": 43
  }
]

另请参阅jq Github问题#684:如何从对象创建数组?


1
非常简单,谢谢 x1000,不需要 -n、-s 或任何花哨的 reduce 表达式。 - Ed Randall

6

要将对象组合成数组,您可以使用以下方法:

$ echo '
{
  "a": "green",
  "b": "white"
}
{
  "a": "red",
  "c": "purple"
}' | jq -n '[inputs]'
[
  {
    "a": "green",
    "b": "white"
  },
  {
    "a": "red",
    "c": "purple"
  }
]

1
你的回答是正确的,但与此页面上已经给出的更简单(更短)的答案相比没有明显的优势(jq -s .); 在这种情况下,仅使用-s可能实际上更快,因为-s执行的处理都是用C编写的。 - peak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接