1

I am pretty new to jq command and stuck at a place to edit a JSON file. I have a JSON file in the format below.

{
  "service": {
    "name": "web",
    "tags": [
      "contact_points"
    ],
    "check": {
      "script": "tmp/status_check.py > /dev/null 2>&1",
      "interval": "10s"
    }
  }
}

I want to modify this JSON to add a nested key/value as following:

{
"service": [{
        "name": "web",
        "tags": [
            "contact_points"
        ],
        "check": {
            "script": "tmp/status_check.py > /dev/null 2>&1",
            "interval": "10s"
        }
    },
    {
        "name": "tomcat",
        "tags": [
            "contact_points"
        ],
        "check": {
            "script": "tmp/status_check.py > /dev/null 2>&1",
            "interval": "10s"
        }
    }
]

}

I tried the below command but it overwrites the contents of the files.

jq '. + { "service": "{"name":"tomcat","tags":["contact_points"],"check":{"script":"tmp/status_check.py > /dev/null 2>&1","interval":"10s"}}" }' /tmp/status.json > /tmp/file && mv /tmp/file /tmp/status.json

and gives the below output

{
  "service": {
    "name": "tomcat",
    "tags": [
      "contact_points"
    ],
    "check": {
      "script": "tmp/status_check.py > /dev/null 2>&1",
      "interval": "10s"
    }
  }
}

I tried escaping the special characters but was not able to get the desired output. Is there any other way of achieving this? any help is greatly appreciated.

3
  • 2
    The output you show as being the desired result is invalid as JSON. I think you intended that there be just one JSON object with just one “service” key, but please correct the post. Commented Oct 5, 2017 at 3:03
  • As it stands this is not a very good question since as peak pointed out the exact output requested does not make much sense. It's not legal JSON and would be rejected by anything expecting legal JSON. It would make more sense to collect the {"service":...} objects in an array, give the second service a different key or perhaps emit two separate objects in a stream. Commented Oct 5, 2017 at 6:45
  • @peak Thanks for checking the syntax. Here is the output I am looking for. { "service": [{ "name": "web", "tags": [ "contact_points" ], "check": { "script": "tmp/status_check.py > /dev/null 2>&1", "interval": "10s" } }, { "name": "tomcat", "tags": [ "contact_points" ], "check": { "script": "tmp/status_check.py > /dev/null 2>&1", "interval": "10s" } } ] } Commented Oct 5, 2017 at 17:40

2 Answers 2

1

If your goal is just to take the single service and duplicate it with a new name, then you could do this:

.service |= [., .name = "tomcat"]

https://jqplay.org/s/33L3zA9Fos

That is, update the service property (.service |= ...) by creating an array with the current item, and another copy where the name property is "tomcat".

Sign up to request clarification or add additional context in comments.

1 Comment

Awesome! This is what I was looking for. Thanks for your answers.
0

Thank you for updating your question. Since in your input .service is an object and in your output .service is an array, here is a solution which uses a helper function:

def as_array:if type=="object" then [.] else . end;

.service |= as_array + [
   {
     "name": "tomcat",
     "tags": [
       "contact_points"
     ],
     "check": {
        "script": "tmp/status_check.py > /dev/null 2>&1",
        "interval": "10s"
     }
   }
]

If the above filter is in filter.jq and your sample data in status.json, the command

$ jq -M -f filter.jq status.json

produces

{
  "service": [
    {
      "name": "web",
      "tags": [
        "contact_points"
      ],
      "check": {
        "script": "tmp/status_check.py > /dev/null 2>&1",
        "interval": "10s"
      }
    },
    {
      "name": "tomcat",
      "tags": [
        "contact_points"
      ],
      "check": {
        "script": "tmp/status_check.py > /dev/null 2>&1",
        "interval": "10s"
      }
    }
  ]
}

If you want to replace the existing status.json with this output you can use a solution such as sponge(1) from moreutils e.g.

$ jq -M -f filter.jq status.json | sponge status.json

1 Comment

Thanks for your reply. This solves my problem as well. Since I can mark only one answer as correct I will mark Jeff's answer as it is short and concise. Thanks again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.