简体   繁体   中英

jq JSON display all values on same line

I am sure this is simple, but I have been trying for hours.

I want to display the two values in each object under the appservice array, and list both values per block on one line along with the relevant IP and name.

My JSON is like this:

{
  "allow": [
    {
      "name": "username1",
      "scm": "true",
      "ipstart": "192.168.1.2",
      "ipend": "192.168.1.2",
      "cidr": "/32",
      "resources": [
        {
          "appservice": [
            {
              "resourcegroup": "resourcegroup1",
              "resource": "resource1"
            },
            {
              "resourcegroup": "resourcegroup2",
              "resource": "resource2"
            }
          ]
        },
        {
          "sqlserver": [
            {
              "resourcegroup": "resourcegroup3",
              "resource": "resource3"
            },
            {
              "resourcegroup": "resourcegroup4",
              "resource": "resource4"
            }
          ]
        }
      ]
    },
    {
      "name": "username2",
...
...

and I want to end up like this:

192.168.1.2 resourcegroup1 resource1 username1
192.168.1.2 resourcegroup2 resource2 username1

192.168.1.3 resourcegroup5 resource5 username2
192.168.1.3 resourcegroup6 resource6 username2

I have tried:

jq -r '.allow[] | "\(.ipstart) \(.resources[].appservice[]?.resourcegroup) \(.resources[].appservice[]?.resource) \(.name)"' test.json

which must be iterating too many times, as I get double the lines and the "resourcegroup" names are not matching the "resource" names

192.168.1.2 resourcegroup1 resource1 username1
192.168.1.2 resourcegroup2 resource1 username1
192.168.1.2 resourcegroup1 resource2 username1
192.168.1.2 resourcegroup2 resource2 username1
192.168.1.3 resourcegroup5 resource5 username2
192.168.1.3 resourcegroup6 resource5 username2
192.168.1.3 resourcegroup5 resource6 username2
192.168.1.3 resourcegroup6 resource6 username2

And I tried:

jq -r '.allow[] | "\(.ipstart) \(.resources[].appservice[]? | .[])  \(.name)"' test.json

which gives me:

192.168.1.2 resourcegroup1  username1
192.168.1.2 resource1  username1
192.168.1.2 resourcegroup2  username1
192.168.1.2 resource2  username1
192.168.1.3 resourcegroup5  username2
192.168.1.3 resource5  username2
192.168.1.3 resourcegroup6  username2
192.168.1.3 resource6  username2

I tried other combos as well, but the above were the closest. I could do some sed/awk work to re-parse the jq output, but I'm sure there must be some really simple way via jq to avoid having to re-parse it.

This simple variation should not have the Cartesian product problem of your attempt. Your mistake seems to be introducing the string interpolation too early.

jq -r '.allow[]
       | {ipstart,name} + .resources[].appservice[]?
       | "\(.ipstart) \(.resourcegroup) \(.resource) \(.name)"
' file.json

There might be a shorter way, but this seems to work:

jq -r '.allow[]
       | .ipstart as $ip | .name as $name
       | .resources[].appservice | select(.)
       | .[].name |= $name | .[].ip |= $ip
       | .[] | [.ip, .resourcegroup, .resource, .name]
       | @tsv
' file.json

If you want space-separated values (without regard to whether the values contain spaces), you could use join/1 :

jq -r '.allow[]
   | [.ipstart] 
     + (.resources[].appservice[]?
        | [.resourcegroup, .resource]) 
     + [.name]
   | join(" ")
 ' file.json 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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