1

I have a bash string default with content

$ echo $default
{
    "horses": {
        "count": 0,
        "fizz": "buzz"
    },
    "admin": {
        "enabled": false
    }
}

and a file override.json with content

$ cat override.json
{
    "horses": {
        "count": 1,
        "foo": "bar"
    },
    "admin": {
        "enabled": true
    }
}

I want to recursively merge these using jq to produce the result

{
    "horses": {
        "count": 1,
        "foo": "bar",
        "fizz": "buzz"
    },
    "admin": {
        "enabled": true
    }
}

I've tried to understand the docs and a few things like

jq -s '.[0] * .[1]' $(echo $default) override.json

but my bash and stream skills are limited.

blueski
  • 58
  • 6

2 Answers2

2

Incidentally, your default variable is almost (!) valid jq program/filter (albeit not valid JSON). If you quote the value in the fizz:buzz line (change to fizz: "buzz"), then you could use it directly as the LHS of the recursive-merge operator:

jq "$default * ." override.json

With the updated question (which now has valid JSON in the default variable), jq should be invoked as follows:

jq --argjson defaults "$default" '$defaults * .' override.json
knittl
  • 246,190
  • 53
  • 318
  • 364
  • How is the line `fizz: buzz` valid jq? You'd at least need something along the lines of `jq "def buzz: \"buzz\"; $default * ." override.json`. – pmf Feb 24 '23 at 09:07
  • @pmf you are right, I missed that the string value was not quoted. Thanks for the heads up. – knittl Feb 24 '23 at 09:28
  • Thank you! Look so simple now that i see it. – blueski Feb 24 '23 at 09:52
  • (The non-valid JSON was a error from my part obfuscating my real data. Edited my question now.) – blueski Feb 24 '23 at 09:54
  • @blueski Generally speaking, you should very much avoid injecting data into code, as jq offers plenty of possibilities to do it in a safe manner. One would be using the `--argjson` option: `jq --argjson default "$default" '$default * .' override.json`. Less concise, yet way less error-prone as well. – pmf Feb 24 '23 at 10:05
  • With the updated question, this becomes more or less a duplicate of https://stackoverflow.com/questions/75391973/transfer-or-merge-only-some-properties-from-one-json-file-to-another-with-jq (only merging all properties) – knittl Feb 24 '23 at 10:51
1

stedolan/jq would be a good choice to process JSON content. But the content of $default is not valid JSON (it lacks string quoting, coompare it to the file's content which is valid JSON).

However, the variable's content is valid YAML (a superset of JSON), so using a YAML-processor will work. Here are a few options:

Using itchyny/gojq:

gojq --yaml-input --slurpfile in override.json '. * $in[0]' <<< "$default"
{
  "admin": {
    "enabled": true
  },
  "horses": {
    "count": 1,
    "fizz": "buzz",
    "foo": "bar"
  }
}

Using kislyuk/yq:

yq --argfile in override.json '. * $in' <<< "$default"
{
  "horses": {
    "count": 1,
    "fizz": "buzz",
    "foo": "bar"
  },
  "admin": {
    "enabled": true
  }
}

Using mikefarah/yq:

yq -o json '. * load("override.json")' <<< "$default"
{
  "horses": {
    "count": 1,
    "fizz": "buzz",
    "foo": "bar"
  },
  "admin": {
    "enabled": true
  }
}
pmf
  • 24,478
  • 2
  • 22
  • 31
  • Thank you! The non-valid JSON was a error from my part obfuscating my real data. I edited my question now. – blueski Feb 24 '23 at 09:56