3

Lets say this is my json file content:

[ { "id":"45" }, { "id":"56" }, { "id":"13" }, { "id":"5" } ]

and I want to find out if id "13" is in the json file. Is there an way to do this in bash?

I tried to run the command with jq and all sorts of different variations of it (with contain and without for example) and nothing answers this query for me.

Old Pro
  • 24,624
  • 7
  • 58
  • 106
papi
  • 227
  • 1
  • 4
  • 11
  • 1
    yes, there is [jq](https://stedolan.github.io/jq/)... – MarcoLucidi Jul 26 '20 at 08:41
  • True, but I can not find the command that does this specific action – papi Jul 26 '20 at 08:47
  • Does this answer your question? [How to check if element exists in array with jq](https://stackoverflow.com/questions/43259563/how-to-check-if-element-exists-in-array-with-jq) – Maroun Jul 26 '20 at 08:48
  • not so much.... – papi Jul 26 '20 at 09:03
  • maybe something like this: `echo '[ { "id":"45" }, { "id":"56" }, { "id":"13" }, { "id":"5" } ]' | jq '[.[].id] | index("13") | . != null'`. this will print `true` if object with id `"13"` is contained, `false` otherwise. but I'm sure there are better ways of doing it... – MarcoLucidi Jul 26 '20 at 09:10
  • 1
    You could use [`xidel`](http://videlibri.sourceforge.net/xidel.html): `xidel -s input.json -e '$json()/id=13'` would return `true`. – Reino Jul 26 '20 at 09:58

3 Answers3

3

Note: when the question was closed, I added this answer to the question in an effort to get the question reopened:

(( $(jq < file.json '[.[].id | select(. == "13")] | length') > 0))

The OP said it was inefficient. I do not know why. Here is what it does:

  1. It passes the JSON through the jq program, which is a JSON parser. The bash shell has no native understanding of JSON, so any solution is going to make use of an external program. Other programs will treat JSON as text, and may work in some or most cases, but it is best to use a program like jq that follows the formal JSON specification to parse the data.

  2. It creates an array to capture the output of...

    1. It loops through the array, picking out all the id fields

    2. It outputs the value of the id field if the value is "13"

  3. It counts the length of the array, which is the number of the id fields whose value is "13"

  4. Using native bash, it converts that output into a number and evaluates to true if the number is greater than 0 and false otherwise.

I do not think you will find something significantly more efficient that formally follows the JSON spec.

  • This only runs 1 program, jq, which is the de facto standard JSON processor. It is not part of the POSIX standard (which predates JSON) but it is the most likely JSON processor to be installed on a system.
  • This uses native bash constructs to interpret the output and to the test.
  • There is not going to be a solution that is more efficient because it runs zero programs (bash cannot do it alone) and there is not going to be a better program to use than jq.
  • There is not going to be a significantly better jq filter, because it is going to process the entire input (that is just how it works) and the select filter stops the processing of objects that fail the test, which is all or almost all of them.

The alternative "peak" suggests is more compact and more elegant (good things) but not significantly more (or less) efficient. It looks better in the post because a lot is left out. The full test would be

[[ $(jq < file.json 'any(.[]; .id == "13")') == "true" ]]

Actually, the .[]; generator is unnecessary, so the even more compact answer would be

[[ $(jq < file.json 'any(.id == "13")') == "true" ]]
Old Pro
  • 24,624
  • 7
  • 58
  • 106
2

Here is one simple way to to determine if a given "id" value is present using perl:

echo '[ { "id":"45" }, { "id":"56" }, { "id":"13" }, { "id":"5" } ]' | perl -00 -lne 'if (/"id":"13"/) {print "true"} else {print "false"}'
true

echo '[ { "id":"45" }, { "id":"56" }, { "id":"13" }, { "id":"5" } ]' | perl -00 -lne 'if (/"id":"33"/) {print "true"} else {print "false"}'
false
LeadingEdger
  • 604
  • 4
  • 7
  • Using regular expressions to parse formal data structures is likely to be inaccurate in some cases. Your example would miss `[ { "id": "13" } ]` and would include `{"key":{"id":"13"}}` for just 2 examples. Although JSON is not as complex as HTML, many of the arguments against using regular expressions to parse HTML expressed in [this classic post](https://stackoverflow.com/a/1732454/712765) remain applicable. – Old Pro Jul 29 '20 at 16:57
1

Here is one possibility:

any(.[]; .id == "13")
peak
  • 105,803
  • 17
  • 152
  • 177