我正在尝试使用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": . }
我如何将这两个过滤器的输出合并在一起,以使每个输入标志行都映射到没有/一个/两个可选字段的单个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实现此目的的最佳方法是什么?
捕获功能似乎适合您的任务。
从manual:capture(regex; flags)
“将命名捕获捕获到JSON对象中,每个捕获的名称作为键,匹配的字符串作为相应的值。”
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"
}
最后一行通过删除非数字并将结果转换为数字来更新这些对象中的值。