1

My json will look like.

{
  "cgi_json_version": "1.8.0",

  "status": {

    "hostgroup_summary": [

      { "hostgroup_name": "ESXI",
        "hosts_up": 9, "hosts_down": 0,
        "hosts_down_unacknowledged": 0, "hosts_down_scheduled": 0,
        "hosts_down_acknowledged": 0, "hosts_down_disabled": 0,
        "hosts_unreachable": 0, "hosts_unreachable_unacknowledged": 0,
        "hosts_unreachable_scheduled": 0, "hosts_unreachable_acknowledged": 0,
        "hosts_unreachable_disabled": 0, "hosts_pending": 0,
        "services_ok": 0, "services_warning": 0,
        "services_warning_unacknowledged": 0, "services_warning_host_problem": 0,
        "services_warning_scheduled": 0, "services_warning_acknowledged": 0,
        "services_warning_disabled": 0, "services_unknown": 0,
        "services_unknown_unacknowledged": 0,
        "services_unknown_host_problem": 0, "services_unknown_scheduled": 0,
        "services_unknown_acknowledged": 0, "services_unknown_disabled": 0,
        "services_critical": 0, "services_critical_unacknowledged": 0,
        "services_critical_host_problem": 0, "services_critical_scheduled": 0,
        "services_critical_acknowledged": 0, "services_critical_disabled": 0,
        "services_pending": 0 
      }

    ]

  }

}

I want to fetch just hosts_up : 9 or simply the number 9, tried many examples but it didn't went well, help me.

chepner
  • 497,756
  • 71
  • 530
  • 681
Kunal Saha
  • 19
  • 5
  • I'm a litle new over here.. tried to format .. but it didn't went well.. but not hoped for a -1 downvote.. strange you guys even downvote instead of encoraging people in a right manner – Kunal Saha Jan 16 '17 at 17:11
  • 1
    Can you show at least one thing you tried that failed? We get a lot of "tried many examples" handwavery, and it *does* tend to be frowned on, as opposed to *concretely* showing effort, vs merely referring to its expenditure. Showing exactly what you tried also means that we can potentially determine exactly what you're misunderstanding about the language, and provide a more useful answer in that respect. – Charles Duffy Jan 16 '17 at 17:15
  • 1
    @mklement0, if everyone who *didn't* downvote added a comment to that effect, then we'd have unmanageable comment feeds. :) (Wasn't me this time either, but I can appreciate why someone would; the title makes a broadly sweeping claim, but the content doesn't back that claim up by showing, ie. that one can fetch *non-numeric* things with strings, or that one can fetch things except with strings, or that the problem applies to simpler data structures than the OP's real-world use case, etc; trying to build a [MCVE](http://stackoverflow.com/help/mcve) would have clarified greatly). – Charles Duffy Jan 16 '17 at 17:21
  • 1
    *nod*. Anyhow, if the OP were engaging here on their end, I'd be happy to help improve the question (though they've already got a good answer, it's worth trying to set an example of what an ideal form of a question would look like so future ones are better received, and I imagine that this question could garner some upvotes if resolved down to an underlying misunderstanding that's not already present in the knowledgebase). Hopefully that'll end up happening here. – Charles Duffy Jan 16 '17 at 17:28

3 Answers3

2

As @mklement0 pointed out, you could just write:

$ jq '.status.hostgroup_summary[].hosts_up' input.json
9

Please note, however, that the .keyname trick only works if the key name is alphanumeric and has a leading alphabetic character (it being understood that _ counts as an alphabetic character here). In general, the form .["KEY"] is more robust. Thus, one of the many other alternatives would be:

jq '.["status"]["hostgroup_summary"][] | .["hosts_up"]'

To emit an object, you can use the { "KEY" } abbreviation:

$ jq '.status.hostgroup_summary[] | { "hosts_up" }' input.json
{
  "hosts_up": 9
}

If you want an approach that is completely agnostic about the exact location (or locations) of the "hosts_up" key, consider:

$ jq '.. | .hosts_up? | select(.)'

This will fetch all truthy values associated with a "hosts_up" key, if there are any. (Truthy here means neither null nor false.) If you want to fetch all values associated with the given key, you'd have to check for the key's presence:

$ jq '.. | select(type == "object" and has("hosts_up")) | .hosts_up'

With recent versions of jq, this last can be shortened to:

$ jq '.. | objects | select(has("hosts_up")) | .hosts_up'
peak
  • 105,803
  • 17
  • 152
  • 177
  • Above guys.. your downvotes encouraged me to google more and more to find the answer for it and hopefully i found the exact answer for it. – Kunal Saha Jan 16 '17 at 17:45
  • 1
    @KunalSaha, I'd actually argue that peak's answer is more exact, inasmuch as it looks at the precise place in the data you specified for the information you want; whereas `.[]` instead of `status` looks under *all* keys, as opposed to the specific one given. If what you *wanted* was to look under all keys, that should have been specified in the question. – Charles Duffy Jan 16 '17 at 18:01
  • The location-agnostic techniques are great. As for `.[""]`: Unfortunately (as of v1.5), this only works as a filter _on its own_, not as part of a _path_. Even though [the manual](https://stedolan.github.io/jq/manual/#Basicfilters) doesn't mention it, merely double-quoting individual keys of a path works, which strikes me as the better approach. Compare `jq '.status."0key"' <<<'{ "status": { "0key": 1 } }'` to `jq '.status | .["0key"]' <<<'{ "status": { "0key": 1 } }'`. Are there any scenarios where simple double-quoting falls short, and use of `... | .[""]` is the only option? – mklement0 Jan 16 '17 at 19:29
  • 1
    @mklement0 -- .["KEY"] works in all versions of jq but ."keyname" is a relative late-comer. Also, .["KEY1"]|.["KEY2"] can be abbreviated as in: jq -n '{a: {b: {c:1}}} | .["a"]["b"]["c"]' – peak Jan 16 '17 at 20:23
2

With your sample input, extracting the value of interest is straightforward, using the appropriately constructed path to the key of interest:

$ jq '.status.hostgroup_summary[0].hosts_up' file
9

Subkey hostgroup_summary of top-level key status is an array, hence the need to use [0] to target the first element.

A value of any JSON type can be retrieved this way, whether it is a number or not, and technically the output is always a string, though jq by default preserves the JSON value formatting (unquoted output of numbers and Booleans, double-quoted output otherwise; arrays as in JSON).
For scalar values, you can add option -r (raw output) to omit the double quotes.


If the array contained multiple entries and you want to extract them all, simply use [] instead of [0]:

$ jq '.status.hostgroup_summary[].hosts_up' file
9

Note with only a single array element the results are the same, but if you had multiple ones, each value would print on a separate line.


To return the entry/ies as a whole, as JSON strings containing the key as well, use the following, as also demonstrated in peak's answer:

$ jq '.status.hostgroup_summary[] | { "hosts_up" }' file
{
  "hosts_up": 9
}

On a side note: If your path contains keys that do not start with an ASCII letter, digit, or _, you must double-quote them; e.g.

$ jq '.status."0key"' <<<'{ "status": { "0key": 9 } }' # Note the "..." around 0key
9
Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775
-3
| jq -r '.[] | .[] | .[] | .hosts_up'  

Above guys.. your downvotes encouraged me to google more and more to find the answer for it and hopefully i found the exact answer for it.

Reference - Using jq to fetch key value from json output

I'm a system admin and i can't show all my hit and trial things all along here.. hope you gonna understand !

Community
  • 1
  • 1
Kunal Saha
  • 19
  • 5
  • Could you explain why the answer given by peak doesn't work for you? (When I test it with the data in the question, it behaves perfectly). – Charles Duffy Jan 16 '17 at 17:55
  • 1
    ...btw -- we're *all* (well, a great many of us in the jq and bash tags, anyhow) sysadmins. It's not that we're asking you to show work product containing proprietary data; rather, we're asking you to break down your problem to the smallest possible reproducer, and show that reproducer. Please see http://stackoverflow.com/help/mcve, or http://sscce.org/, for a detailed guide of what we expect from a code sample showcasing a problem. That's not just busywork: It helps to ensure that answers will be useful, and makes your question useful to others (which is the whole point of the site!) – Charles Duffy Jan 16 '17 at 17:56
  • 1
    Actually, I back that out: **This doesn't work with the data you gave in your question**. With jq 1.5, copy-and-pasting the exact data in the question, I get `jq: error (at :32): Cannot iterate over string ("1.8.0")`. Thus, this answer may work for your *real* data, but in the context of this question as-asked, it's wrong. – Charles Duffy Jan 16 '17 at 18:02
  • 1
    @KunalSaha: Down-votes aren't set in stone. If you improve your question, future readers may up-vote it. The "above guys" are likely long gone, however (unlike the people engaging with you here, who were _not_ the down-voters), and adding an answer that poorly matches the still poorly-worded question will be of benefit to no one (leaving aside that the answer in its current form doesn't even work). – mklement0 Jan 16 '17 at 18:13
  • 1
    @CharlesDuffy is correct. The proposed approach is dubious but it can be made to work by sprinkling enough postfix "?"s on the query. With the given data, it happens that just one is enough: jq -r '.[] | .[]? | .[] | .hosts_up'. However a better agnostic approach would probably be: jq -r '.. | .hosts_up? | select(.)' – peak Jan 16 '17 at 18:28
  • Yes @Charles, it worked fine for me.. i'm not just pasting the exact code and the output just bcoz don't know to format it well, like you guys do and don't want to get a downvote for any xyz reason anymore.. it'z a right answer for the same input.. may be my approach is too dumb .. but for me an stdout means .. ;) don't take in a wrong way.. – Kunal Saha Jan 16 '17 at 18:30
  • @KunalSaha, if you `git clone https://gist.github.com/charles-dyfis-net/f86ca2d470e45e9bd83d14116b1b60cf test.d && cd test.d && bash test.sh`, do you get anything other than the error I pasted? (That gist contains the same JSON given in your question, being run by the same jq query given in this answer). – Charles Duffy Jan 16 '17 at 18:41
  • 1
    ...as for formatting, if you select a block of code and click the `{}` button in the editor, that'll take care of it. – Charles Duffy Jan 16 '17 at 18:42
  • 1
    @CharlesDuffy: I think he's saying he's decided not to show matching input, because he doesn't want to learn how to format properly. KunalSaha: Not making the sample input work with your answer is no way to avoid down-votes - quite the opposite. To paste a _block_ of text and code-format it, paste it, _select it_, and then click the `{}` icon or press `Ctrl-K` - again, http://meta.stackexchange.com/a/22189/248777 will tell you all this. If you learn these simple techniques, you'll be able to ask better questions (and post better self-answers, if applicable), to the benefit of everyone. – mklement0 Jan 16 '17 at 19:46