jsonjq

Convert json structure and conditional update values using environment variables with JQ


I have the following json:

{
  "Parameters": {
    "AmiId": "/my/image/id/latest",
    "InstanceType": "t3.medium",
    "Environment": "$ENV_DEFINITION"
  }
}

And I have exported the $ENV_DEFINITION with the value dev.

NOTE: I want to keep the literal value $ENV_DEFINTION if the environment variable is not set. That's why I'm using the // . part when accessing the env[] array in the command below.

I need to obtain the following output:

'AmiId=/my/image/id/latest' 'InstanceType=t3.medium' 'Environment=dev'

I'm able to get the above output witht he following jq command:

jq -r '[ .Parameters | to_entries[] | .value |= (env[.[1:]] // .) | [.key, .value] | join("=") ] | @sh' < myfile.json

But then I needed to add a few more parameters to json:

{
  "Parameters": {
    "AmiId": "/my/image/id/latest",
    "InstanceType": "t3.medium",
    "Environment": "$ENV_DEFINITION",
    "MinSize": 0,
    "MaxSize": 0,
    "DesiredCapacity": 0,
  }
}

And jq started to fail with the following message:

jq: error (at myfile:10): Cannot index number with object

Well, looks like it fails when the json values are integer as it cannont index integer values at the following place: env[.[1:]].

Then I came up with this new jq command:

jq -r '[ .Parameters | to_entries[] | select((.value|tostring)|startswith("$")) |= (env[.[1:]] // .) | [.key, .value] | join("=") ] | @sh' < myfile.json

But now, this fail when trying to replace the $ENV_DEFINITION. If I take it out of the json file, the above command works.

The error message is:

jq: error (at myfile.json:5): Cannot index object with object

I have tried the following

jq -r '[ .Parameters | to_entries[] | .value |= if ((.value|tostring)|startswith("$")) then (env[.[1:]] // .) else . end | [.key, .value] | join("=") ]' < myfile.json

But:

jq: error (at myfile.json:5): Cannot index string with string "value"

I'm still fighting with jq and it's documentation here to figure out what to do but any help will be welcome.


Solution

  • To only trigger the lookup if the value is a string, you can use select(type == "string"), which also has the strings shortcut. So, in your first attempt, just replace .[1:] with strings[1:], and you should be good to go.

    jq -r '[ .Parameters | to_entries[] | .value |= (env[strings[1:]] // .) | [.key, .value] | join("=") ] | @sh' < myfile.json