4

I have a JSON file I'm reading into a bash script and would like to prepend a fixed string to each key.

json_file:

{"key_1": 12, "key_2": 34, "key_3": 56}

What's the cleanest way I can update this data by prepending the string x_ to each key?

For example,

{"x_key_1": 12, "x_key_2": 34, "x_key_3": 56}
3
  • Is that your correct json format? All key-values in the same line? Oct 21, 2022 at 19:01
  • Sorry, yeah this is all in one line. It was a json.dump() call from Python. All values are integers.
    – user546158
    Oct 21, 2022 at 21:08
  • 1
    @user546158 If it came from a Python script, then it would possibly be better to make this change in the script rather than as a post-processing step.
    – Kusalananda
    Oct 22, 2022 at 14:50

3 Answers 3

7

You can use a JSON parser such as jq to parse your JSON file. The advantage of this is that valid JSON can be handled regardless of its shape:

jq 'with_entries(.key |= "x_" + .)' <file.json

Input

{"key_1": 12, "key_2": 34, "key_3": 56}

Output

{
  "x_key_1": 12,
  "x_key_2": 34,
  "x_key_3": 56
}

You can keep the JSON on one line with jq -c …:

{"x_key_1":12,"x_key_2":34,"x_key_3":56}

This solution is shown as an example in the documentation for jq - see man jq and search for with_entries - but as it's a reference document it can be hard to find things you don't know how to describe.

0
0

Taking the question in the title literally, the following appends some user-provided string to all keys in the input document recursively:

jq --arg prefix x_ '
    walk(
        if type == "object" then 
            with_entries(.key = $prefix + .key)
        else . end
    )' file

The key is updated similarly to what's done in roaima's answer, but without using the update operator. The prefix string is also given on the command line instead of being a hard-coded string.

Test run:

$ cat file
{
  "key_1": 12,
  "key_2": 34,
  "key_3": [
    {
      "key_1": "{\"key_A\":123}",
      "key_2": 34,
      "key_3": 56
    },
    {
      "key_1": "{\"key_A\":123}",
      "key_2": 34,
      "key_3": 56
    }
  ]
}
$ jq --arg prefix x_ 'walk(if type == "object" then with_entries(.key = $prefix + .key) else . end)' file
{
  "x_key_1": 12,
  "x_key_2": 34,
  "x_key_3": [
    {
      "x_key_1": "{\"key_A\":123}",
      "x_key_2": 34,
      "x_key_3": 56
    },
    {
      "x_key_1": "{\"key_A\":123}",
      "x_key_2": 34,
      "x_key_3": 56
    }
  ]
}
0

If your json format is in one-line then the following should work:

sed -i 's/"\([^"]*\)":/"x_\1":/g' json_file.json

If your json format looks like this:

{
   "key_1": 1, 
   "key_2": "v2", 
   "key_3": 3
}

You could use the sed command above but you also can use the following sed which is a little easier:

sed -i 's/"\(.*\)":/"x_\1":/'  json_file.json

Note: The solution above works well if you just have numbers or strings that don't have the following pattern:

{ "key_1": "\"Sale\": foobar" }
// Or
{ "\"key_1\"": "\"Sale\": foobar" } // I think  this case is less common

So the best way to edit the keys correctly is by using the roaima's answer. I tried another possible solution with sed (but I'm not sure if there are other cases where it might fail). If your json file looks like this:

{"key_1": "\"Sale\": foobar", "key_2": "\"3\":", "key_3": 56}
// Or maybe
{"key_1": "\"Sale:sale\": foobar", "key_2": "\"3\":", "key_3": 56}

you can try using:

sed -i 's/"\([^"\][^"\]*\)":/"x_\1":/g' json_file.json

However the command above will fail if the json file looks like this:

{"\"key_1\"": "\"Sale:\": foobar", "key_2": "\"3\":", "key_3": 56}
// If the json keys  have \"somekey\" as their keys then the sed command will fail. 
// So using sed for this task might be a little tricky for avoiding these problems.
4
  • 1
    Thank you, the first command solved my problem!
    – user546158
    Oct 21, 2022 at 21:17
  • I'm not sure why this was down-voted but no problem. However if it's for v1, v2 and v3 I know are not valid and they must be numbers or between " but the OP had specified those values (the question was edited after my answer). The command works either the values are number or not. Maybe I did not consider some cases where the command will not work as expected. Oct 22, 2022 at 1:47
  • If one of the values is the JSON string "\"Sale\": foobar", it would be modified into "\"x_Sale\": foobar" by your sed command.
    – Kusalananda
    Oct 22, 2022 at 14:49
  • @Kusalananda thank you! I appreciate the comment! I had no idea about that case. I'll try to change the sed command anyway. Oct 22, 2022 at 15:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .