简体   繁体   English

Bash脚本使用jq遍历多行JSON对象

[英]Bash script traversing a multi-line JSON object using jq

I have to curl to a site (statuscake.com) that sends multiple items back in a JSON, each line of which contains multiple items. 我必须卷曲到一个站点(statuscake.com),该站点以JSON返回多个项目,其中每行包含多个项目。 I want to extract from each line two of them, WebsiteName and TestID, so I can check if WebsiteName matches the one I'm interested in, get the TestID out and pass this to a second curl statement to delete the test. 我想从每行中提取其中两个,WebsiteName和TestID,因此我可以检查WebsiteName是否与我感兴趣的匹配,将TestID取出并将其传递给第二个curl语句以删除测试。

Although it's more complex, the JSON that comes back is essentially of the form 尽管更为复杂,但返回的JSON本质上具有以下形式

[{"TestID": 123, "WebsiteName": "SomeSite1"}, {"TestID": 1234, "WebsiteName": "SomeSite2"}]

I can't seem to find a magic jq command to do it all in one - if there is one, I'd be really happy to see it. 我似乎找不到一个神奇的jq命令来一次完成所有操作-如果有一个,我会很高兴看到它。

I've got 我有

cat $data | jq '[.[] | .WebsiteName]' 

to get an array of the website names (and a very similar one for the TestIDs, but I think I've done something daft. data is the information coming back from the curl to get the JSON and that's populated OK. 以获得一组网站名称(与TestIDs非常相似),但我认为我做得有些愚蠢。数据是从curl返回的信息,用于获取JSON,因此填充好。

I want to be able to assign these to two arrays, names and ids, then search names for the index of the relevant name, grab the id from ids and pass that to the curl. 我希望能够将它们分配给两个数组,即名称和ID,然后在名称中搜索相关名称的索引,从ID中获取ID并将其传递给curl。 Unless there's a better way. 除非有更好的方法。

Any advice please? 有什么建议吗?

My Xidel can do it all at once by selecting the JSON with a XPath-like query: 通过使用类似XPath的查询选择JSON,我的Xidel可以一次完成所有操作:

Eg return all ids where the WebsiteName contains "site2" from an array of objects: 例如,从对象数组中返回WebsiteName包含“ site2”的所有ID:

xidel /tmp/x.json -e '$json()[contains((.).WebsiteName, "site2")]/TestID'

Or eg to download the original JSON and then make the HTTP request with the ids: 或者,例如,下载原始JSON,然后使用ID发出HTTP请求:

xidel http://statuscake.com/your-url... -f '$json()[contains((.).WebsiteName, "site2")]/TestID!x"/your-delete-url{.}..."'

If I'm getting your question right, it sounds like what you want is to, for each element, select those where .WebsiteName == "needle" , and then get .TestID from it. 如果我的问题正确.WebsiteName == "needle" ,这听起来像是您想要的,对于每个元素,选择.WebsiteName == "needle"那些元素,然后从中获取.TestID You can do just that: 您可以这样做:

.[] | select(.WebsiteName == "needle") | .TestID

If you want an array as the result, you can wrap the above script in square brackets. 如果要使用数组作为结果,可以将以上脚本包装在方括号中。

The jq filters startswith and endswith may be of interest to you. 该JQ过滤器startswithendswith可能是你的兴趣。 If you're going to pass the result back to cURL, you may also be interested in the @sh formatting filter and the -r command-line flag. 如果要将结果传递回cURL,您可能还对@sh格式过滤器和-r命令行标志感兴趣。

Assuming you have a bash 4+ and assuming the json is valid (does not contain newlines in strings, etc.) this works: 假设您的bash为4+,并假设json有效(字符串中不包含换行符,等等),则此方法有效:

$ echo "$data"
[{"TestID": 123, "WebsiteName": "SomeSite1"}, {"TestID": 1234, "WebsiteName":
"SomeSite2"}, {"TestID": 555, "WebsiteName": "foo*ba@r blah[54]quux{4,5,6}"}]
$ declare -A arr
$ while IFS= read -r line; do
    eval "$line"
done < <(jq -M -r '.[] | @sh "arr[\(.WebsiteName)]+=\(.TestID)"' <<<"$data")
$ declare -p arr
declare -A arr='(["foo*ba@r blah[54]quux{4,5,6}"]="555" [SomeSite2]="1234" [SomeSite1]="123" )'

Here is a solution using only jq primitives. 这是仅使用jq原语的解决方案。

  .[]
| if .WebsiteName == "SomeSite1" then .TestID else empty end

This is essentially the same as Santiago 's answer but if you are new to jq it may be informative because select/1 is defined as 这基本上与Santiago的答案相同,但是如果您不熟悉jq,它可能会提供参考,因为select / 1定义为

 def select(f): if f then . else empty end;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM