Reputation: 2805
I've read almost every question I can find on SO with the same general premise and I've gotten close three different times, but I just can't make this work.
Given a JSON file called parameters.json
with keypairs like so; (shortened for sharing purposes)
[
{
"ParameterKey": "Foo1",
"ParameterValue": "Bar1"
},
{
"ParameterKey": "Foo2",
"ParameterValue": "Bar2"
}
]
I want to add another keypair, say
{
"ParameterKey": "Foo3",
"ParameterValue": "Bar3"
}
So I end up with a file like
[
{
"ParameterKey": "Foo1",
"ParameterValue": "Bar1"
},
{
"ParameterKey": "Foo2",
"ParameterValue": "Bar2"
},
{
"ParameterKey": "Foo3",
"ParameterValue": "Bar3"
}
]
I'm writing a bash script that copies and updates parameter files for AWS - this is where the keypairs come in. We have a new keypair that needs to be added to any existing files when they're copied. I can get the if/then done fine, it's physically adding the new keypair that is stumping me.
With a ton of googling I ended up with this clunky workaround, which I don't really understand and, while it generates the keypair just fine, doesn't add it back into parameters.json
item='{"ParameterKey": "RTSMSnapshotID"}'
jq --argjson item "$item" '$item + {"ParameterValue": ""}' parameters.json
I get the keypair printed back to me correctly on the command line, so I figure add | sponge parameters.json
but that then gives me an empty file.
I also considered a sed workaround that trimmed the last line of the file and then appended the new keypair (and EOF) but of course sed doesn't play well with newlines and I can't get it to work.
I'm open to solutions that use anything in bash and anything in jq. I am still a bash/jq noob so detailed explanations are appreciated.
Upvotes: 1
Views: 5109
Reputation: 116967
If you have one file with a JSON array (say parameters.json), and one or more additional files (say file*.json) with JSON entities that you want to append to the array in the first file, and if you want to overwrite the first file, here's a rather sly solution, which however requires jq 1.5 or later:
$ jq 'reduce inputs as $in (.; . + [$in])' parameters.json file*.json |
sponge parameters.json
Note that using this approach, each top-level JSON entity in each of the auxiliary files will be appended to the array separately.
What makes this a bit crafty is that inputs
is being used here without the -n option.
Since you mentioned bash
, please note that if any of the "file*.json" sources is a process, you could use <( ... )
rather than specifying a filename, e.g.:
$ jq 'reduce inputs as $in (.; . + [$in])' parameters.json <(curl -Ss ...) |
sponge parameters.json
If you don't have sponge
, then you can use the idiom:
jq ..... > OUT && mv IN OUT
Upvotes: 1
Reputation: 85865
The idea of using argjson
is right, but the syntax is as below on jq-1.5
jq --argjson obj '{ "ParameterKey": "Foo3", "ParameterValue": "Bar3" }' '. + [$obj]' < json
[
{
"ParameterKey": "Foo1",
"ParameterValue": "Bar1"
},
{
"ParameterKey": "Foo2",
"ParameterValue": "Bar2"
},
{
"ParameterKey": "Foo3",
"ParameterValue": "Bar3"
}
]
Check the jq-documentation for more information about the +
and +=
operators.
Am not aware of ways to do this in jq
itself, but you can use a neat bash
trick to do this,
jq --argjson obj '{ "ParameterKey": "Foo3", "ParameterValue": "Bar3" }' '. + [$obj]' < json > temp && mv temp json
Upvotes: 4