0

I'm simply trying to replace an objects value in a json file with an array, using jq in a bash script. The json file (truncated) looks like this:

{
  "objects": {
    "type": "foo",
    "host": "1.1.1.1",
    "port": "1234"
  }
}

I want to replace the host objects value with an array of different values, so it looks like this:

{
  "objects": {
    "type": "foo",
    "host": ["1.1.1.1","2.2.2.2"],
    "port": "1234"
  }
}

I tested around with this script. The Input comes from a simple, comma separated string which I convert into a proper json array (which seems to work). But I'm not able replace the value with the array.

#!/bin/bash
objectshost="1.1.1.1,2.2.2.2"
objectshost_array=$(jq -c -n --arg arg $objectshost '$arg|split(",")')

jq --arg value "$objectshost_array" '.objects.host = $value' ./test.json > ./test.json.tmp

The best I ended up with, is this:

{
  "objects": {
    "type": "foo",
    "host": "[\"1.1.1.1\",\"2.2.2.2\"]",
    "port": "1234"
  }
}

The result seems to be some logical result, as the script simply replaces the value with the arrays string. But it's not what I expected to get. ;)

I found some similar questions, but all of them were dealing with replacing values in existing arrays or key/value pairs, but my problem seems to be the conversion from a single value to an array.

Can somebody please push me into the right direction? Or should I forget about jq and threat the json file as a simple text file?

Thanks in advance,
André

buanet
  • 18
  • 1
  • 1
    Import your JSON-encoded variable as JSON using `--argjson` (not as string using `--arg`). `jq --argjson value "$objectshost_array" …`. You can also make the conversion directly (resulting in just one jq call, and then using `--arg` again): `jq --arg value "$objectshost" '.objects.host = ($value|split(","))'` – pmf Feb 15 '23 at 11:27
  • Also see: https://stackoverflow.com/questions/70744916/how-to-use-jq-and-bash-to-inject-a-files-json-array-contents-while-appending – pmf Feb 15 '23 at 11:44
  • For sure, I was playing around with the `--argjson` option before, but I guess without/ before I added the conversion. It always ended up in a `jq: invalid JSON text passed to --argjson`. Now I know why... Lesson learned. Thanks a lot! – buanet Feb 15 '23 at 12:01
  • Also see https://stackoverflow.com/questions/75388052/bash-jq-add-attribute-with-object-value/75388246#75388246 (cannot set as duplicate because it does not have upvotes nor an accepted answer) – knittl Feb 15 '23 at 12:46
  • @knittl, ...it's not without upvote-worthy answers, though, so that can be fixed. :) – Charles Duffy Feb 15 '23 at 14:09

2 Answers2

1

It would work with a conditional assignment from arguments:

jq '
.objects.host = (
  .objects.host |
  if type == "array"
  then .
  else [ . ]
  end + $ARGS.positional
)
' input.json --args 1.2.3.4 2.2.2.2 4.4.4.4

Or the same as a stand-alone jq script; which is more readable and maintainable:

myJQScript:

#!/usr/bin/env -S jq --from-file --args

.objects.host = (
  .objects.host |
  if type == "array"
  then .
  else [ . ]
  end + $ARGS.positional
)

Make it executable:

chmod +x myJQScript

Run it with arguments to add array entries to host

$ ./myJQScript 1.2.3.4 2.2.2.2 4.4.4.4 < input.json
{
  "objects": {
    "type": "foo",
    "host": [
      "1.1.1.1",
      "1.2.3.4",
      "2.2.2.2",
      "4.4.4.4"
    ],
    "port": "1234"
  }
}
Léa Gris
  • 17,497
  • 4
  • 32
  • 41
0

You can do it with a single jq command:

#!/bin/sh
objectshost="1.1.1.1,2.2.2.2"

jq --arg value "$objectshost" '.objects.host = ($value / ",")' ./test.json > ./test.json.tmp

This has the added benefit of not requiring Bash arrays, but can be used with any shell.


If you already have a JSON array, you must use --argjson and not --arg. --arg always creates a variable of type string, --argjson however parses the value as JSON entity.

#!/bin/bash
objectshost="1.1.1.1,2.2.2.2"
objectshost_array=$(printf '%s\n' "$objectshost" | jq -c 'split(",")')

jq --argjson value "$objectshost_array" '.objects.host = $value' ./test.json > ./test.json.tmp
knittl
  • 246,190
  • 53
  • 318
  • 364