How to find something in a json file using Bash

Viewed 929

I would like to search a JSON file for some key or value, and have it print where it was found.

For example, when using jq to print out my Firefox' extensions.json, I get something like this (using "..." here to skip long parts) :

{
  "schemaVersion": 31,
  "addons": [
    {
      "id": "wetransfer@extensions.thunderbird.net",
      "syncGUID": "{e6369308-1efc-40fd-aa5f-38da7b20df9b}",
      "version": "2.0.0",
      ...
    },
    {
      ...
    }
  ]
}

Say I would like to search for "wetransfer@extensions.thunderbird.net", and would like an output which shows me where it was found with something like this:

{ "addons": [ {"id": "wetransfer@extensions.thunderbird.net"} ] }

Is there a way to get that with jq or with some other json tool?

I also tried to simply list the various ids in that file, and hoped that I would get it with jq '.id', but that just returned null, because it apparently needs the full path.

In other words, I'm looking for a command-line json parser which I could use in a way similar to Xpath tools

2 Answers

The path() function comes in handy:

$ jq -c 'path(.. | select(. == "wetransfer@extensions.thunderbird.net"))' input.json
["addons",0,"id"]

The resulting path is interpreted as "In the addons field of the initial object, the first array element's id field matches". You can use it with getpath(), setpath(), delpaths(), etc. to get or manipulate the value it describes.

Using your example with modifications to make it valid JSON:

< input.json jq -c --arg s wetransfer@extensions.thunderbird.net '
  paths as $p | select(getpath($p) == $s) | null | setpath($p;$s)'

produces:

{"addons":[{"id":"wetransfer@extensions.thunderbird.net"}]}

Note

If there are N paths to the given value, the above will produce N lines. If you want only the first, you could wrap everything in first(...).

Listing all the "id" values

I also tried to simply list the various ids in that file

Assuming that "id" values of false and null are of no interest, you can print all the "id" values of interest using the jq filter:

.. | .id? // empty
Related