如何合并由逗号分隔的过滤器生成的 jq JSON 对象

How to merge jq JSON objects generated by comma-separated filters

我正在尝试使用 jq 将一些命令行标志转换为 JSON 等价物。

标志看起来像这样,其想法是将(可选)f 标志转换为 JSON "foo" 字段,将(可选)b 标志转换为 JSON "bar" 字段:

{
  "flags": [
    "f1",
    "b2",
    "f3b4",
    "b6f5"
  ]
}

获取 foo 字段很容易:

.flags[] | match("f([0-9][0-9]*)") | .captures[0].string | tonumber | { "foo": . }

条形字段相同(请说明是否有更好的方法使用 jq 执行此操作):

.flags[] | match("b([0-9][0-9]*)") | .captures[0].string | tonumber | { "bar": . }

如何将这两个过滤器的输出合并在一起,以便每个输入标志行都映射到具有 none/一个/两个可选字段的单个 JSON 对象?

两个相关机制是 jq 的逗号运算符(在多个过滤器之间共享单个流)和 jq 的 + 运算符(将对象合并为单个对象)。应用逗号运算符很简单:

.flags[] | (match("f([0-9][0-9]*)") | .captures[0].string | tonumber | { "foo": . }), (match("b([0-9][0-9]*)") | .captures[0].string | tonumber | { "bar": . })

但是,这会为每个匹配生成一个单独的对象:

{
  "foo": 1
}
{
  "bar": 2
}
{
  "foo": 3
}
{
  "bar": 4
}
{
  "foo": 5
}
{
  "bar": 6
}

所以这里的具体问题是如何使用+运算符将这两个对象连接在一起。我试图在此处获得的最终输出是 foo 和 bar 字段位于同一对象中的位置:

{
  "foo": 1
}
{
  "bar": 2
}
{
  "foo": 3,
  "bar": 4
}
{
  "foo": 5,
  "bar": 6
}

使用 jq 实现此目的的最佳方法是什么?

捕获功能似乎适合您的任务。

来自manualcapture(regex; flags) "Collects the named captures in a JSON object, with the name of each capture as the key, and the matched string as the corresponding value."

jq '.flags[]
| capture("(?<foo>^f\d+$)"),
  capture("(?<bar>^b\d+$)"),
  capture("(?<foo>f\d+)(?<bar>b\d+)"),
  capture("(?<bar>b\d+)(?<foo>f\d+)")
| .[] |= ( sub("\D"; "") | tonumber )'

捕获行创建了这些对象:

{
  "foo": "f1"
}
{
  "bar": "b2"
}
{
  "foo": "f3",
  "bar": "b4"
}
{
  "bar": "b6",
  "foo": "f5"
}

最后一行通过删除非数字并将结果转换为数字来更新这些对象中的值。