JQ Select by child object value with varying parent object name
JQ Select by child object value with varying parent object name
我有 json:
{
"interfaces": {
"UDPInterface": [
{
"connectTo": {
"1.2.3.4:25925": {
"user": "bob",
"password": "aaaaaaaa",
"publicKey": "foirncnqwpnqwopnqrrvn308g9h4b.k"
},
"4.3.2.1:24970": {
"user": "sam",
"password": "bbbbbbbb",
"publicKey": "v09ervn4uvr78cweyclfirnfuq3c9pwper.k"
},
"1.3.4.2:41872": {
"user": "betty",
"password": "cccccccccc",
"publicKey": "crnn497hg3j34f34uvrnfwmnriuhqrmoweje.k"
}
},
"bind": "0.0.0.0:64660"
},
{
"connectTo": {},
"bind": "[::]:54887"
}
]
}
}
并希望能够使用 jq 根据 "user" 值打印 IP 地址行的内容。我可以接近这个:
jq '.interfaces.UDPInterface[0].connectTo."1.2.3.4:25925" | select(.user | contains("bob"))'
但是,这只给了我 1.2.3.4:25925 对象的值:
{"user" : "bob", "password" : "aaaaaaaa", "publicKey" : "foirncnqwpnqwopnqrrvn308g9h4b.k"},
当我需要的是整行时:
"1.2.3.4:25925" : {"user" : "bob", "password" : "aaaaaaaa", "publicKey" : "foirncnqwpnqwopnqrrvn308g9h4b.k"},
但是,如果事先不知道父对象名称(每个 IP address:port 都是唯一的),我无法弄清楚如何构建这样的表达式。
我整天都在为这个问题苦思冥想,一直没弄明白。任何帮助将不胜感激!
"The whole line" 本身不是有效的 JSON 对象。您可以获得一个包含与您的谓词匹配的所有元素的对象;这将是这样做的一种方式:
jq '.interfaces.UDPInterface[0].connectTo | with_entries(select(.value.user | contains("bob")))'
给定输入的输出为:
{
"1.2.3.4:25925": {
"user": "bob",
"password": "aaaaaaaa",
"publicKey": "foirncnqwpnqwopnqrrvn308g9h4b.k"
}
}
这是一个使用 tostream、select 和 foreach 的解决方案使用 "user:"bob" 和 return 枚举对象的路径 getpath
foreach ( tostream
| select(length == 2 and .[0][-1] == "user" and .[1] == "bob")
| .[0]
) as $p (
.
; .
; { ($p[-2]): getpath($p[:-1]) }
)
编辑:我现在意识到 foreach E as $X (.; .; R)
形式的过滤器几乎总是可以重写为 E as $X | R
所以上面的实际上只是
( tostream | select(length == 2 and .[0][-1] == "user" and .[1] == "bob") | .[0] ) as $p
| { ($p[-2]): getpath($p[:-1]) }
我有 json:
{
"interfaces": {
"UDPInterface": [
{
"connectTo": {
"1.2.3.4:25925": {
"user": "bob",
"password": "aaaaaaaa",
"publicKey": "foirncnqwpnqwopnqrrvn308g9h4b.k"
},
"4.3.2.1:24970": {
"user": "sam",
"password": "bbbbbbbb",
"publicKey": "v09ervn4uvr78cweyclfirnfuq3c9pwper.k"
},
"1.3.4.2:41872": {
"user": "betty",
"password": "cccccccccc",
"publicKey": "crnn497hg3j34f34uvrnfwmnriuhqrmoweje.k"
}
},
"bind": "0.0.0.0:64660"
},
{
"connectTo": {},
"bind": "[::]:54887"
}
]
}
}
并希望能够使用 jq 根据 "user" 值打印 IP 地址行的内容。我可以接近这个:
jq '.interfaces.UDPInterface[0].connectTo."1.2.3.4:25925" | select(.user | contains("bob"))'
但是,这只给了我 1.2.3.4:25925 对象的值:
{"user" : "bob", "password" : "aaaaaaaa", "publicKey" : "foirncnqwpnqwopnqrrvn308g9h4b.k"},
当我需要的是整行时:
"1.2.3.4:25925" : {"user" : "bob", "password" : "aaaaaaaa", "publicKey" : "foirncnqwpnqwopnqrrvn308g9h4b.k"},
但是,如果事先不知道父对象名称(每个 IP address:port 都是唯一的),我无法弄清楚如何构建这样的表达式。
我整天都在为这个问题苦思冥想,一直没弄明白。任何帮助将不胜感激!
"The whole line" 本身不是有效的 JSON 对象。您可以获得一个包含与您的谓词匹配的所有元素的对象;这将是这样做的一种方式:
jq '.interfaces.UDPInterface[0].connectTo | with_entries(select(.value.user | contains("bob")))'
给定输入的输出为:
{
"1.2.3.4:25925": {
"user": "bob",
"password": "aaaaaaaa",
"publicKey": "foirncnqwpnqwopnqrrvn308g9h4b.k"
}
}
这是一个使用 tostream、select 和 foreach 的解决方案使用 "user:"bob" 和 return 枚举对象的路径 getpath
foreach ( tostream
| select(length == 2 and .[0][-1] == "user" and .[1] == "bob")
| .[0]
) as $p (
.
; .
; { ($p[-2]): getpath($p[:-1]) }
)
编辑:我现在意识到 foreach E as $X (.; .; R)
形式的过滤器几乎总是可以重写为 E as $X | R
所以上面的实际上只是
( tostream | select(length == 2 and .[0][-1] == "user" and .[1] == "bob") | .[0] ) as $p
| { ($p[-2]): getpath($p[:-1]) }