0

I have file like this(exact format):

{ "test": "10" }
{ "games": "30" }
{ "REPOSITORY": "5"}

I want to update the value of key. For example games to 66. So the new file would be:

{ "test": "10" }
{ "games": "66" }
{ "REPOSITORY":"5"}

I used jq with combination of a temporary file

tmp=$(mktemp);
jq '.games = "66"' pair.json > "$tmp" && mv "$tmp" change.json

but got this kind of output.

{
  "test": "10",
  "games": "66"
}
{
  "games": "66"
}
{
  "REPOSITORY": "5",
  "games": "66"
}

where games is written all 3 whereas I just want it be updated only at its position. Furthermore i want the value to be updated using bash variable but that I can try to figure out using --arg after I resolve this issue. Pls assist here.

Humble
  • 21
  • 5
  • 1
    What's the purpose of the temporary file? Just redirect directly to the output file as long as you are not trying to overwrite the same file you are reading from. – tripleee Oct 07 '22 at 12:32

2 Answers2

2

Your input is a stream of objects. As such your filter expression, .games = "66" asserts that the record games is present in each of the object present in the stream.

To update the specific object alone, select it first and assign the required value or update it.

jq -c 'select(has("games")).games = "66"'

To answer OP's clarification on how to do the same with variables, do

jq -c --arg key "games" 'select(has($key))[$key] = "555"'
Inian
  • 80,270
  • 14
  • 142
  • 161
  • Hi @inian, This works perfectly but got one issue trying to pass bash variable like this using --arg parameter : `key="games"; jq --arg key "$key" --compact-output 'select(has($key)).$key = "555"' pair.json` Do you have any understanding of how to solve this when I want to pass a variable and not hardcoded value. – Humble Oct 07 '22 at 13:11
  • Works great. I think small correction would be this for others using it.. Thanks again. key="games";jq -c --arg key "$key" 'select(has($key))[$key] = "555"' pair.json – Humble Oct 07 '22 at 13:25
0

A simple solution is using select with assignment. select will return the special value empty if the condition does not match and the input value if it does match.

select(.games).games = "66"

jq -c to generate compact format, i.e. one JSON object/document per line.

To handle arbitrary names, change the syntax slightly:

select(.["games"])["games"] = "66"

and used with arguments passed via CLI:

jq -r --arg key "$var" 'select(.[$key])[$key] = "66"'
knittl
  • 246,190
  • 53
  • 318
  • 364