Home > Enterprise >  How to insert a line after a match using sed (or awk) in a formatted JSON file?
How to insert a line after a match using sed (or awk) in a formatted JSON file?

Time:11-29

{
  "id": "a1234567-89ab-cdef-0123-456789abcdef",
  "properties": {
    ...
    "my_id": "c1234567-89ab-cdef-0123-456789abcdef",
    ...
}

Given the above in a file, I want to be able to perform a match (including the 4 leading spaces) on my_id and then append a new line "my_value": "abcd",. The desired output would look like this:

{
  "id": "a1234567-89ab-cdef-0123-456789abcdef",
  "properties": {
    ...
    "my_id": "c1234567-89ab-cdef-0123-456789abcdef",
    "my_value": "abcd",
    ...
}

Using examples online, I'm unable to get the command to work. Here is an example of something I have tried: sed '/.*"my_id".*/a "my_value": "abcd",' test.json, for which I receive the following error: command a expects \ followed by text.

What is the correct way to structure this command?

CodePudding user response:

Using any awk:

$ awk -v new='"my_value": "abcd",' '{print} sub(/"my_id":.*/,""){print $0 new}' file
{
  "id": "a1234567-89ab-cdef-0123-456789abcdef",
  "properties": {
    ...
    "my_id": "c1234567-89ab-cdef-0123-456789abcdef",
    "my_value": "abcd",
    ...
}

I'm using this:

sub(/"my_id":.*/,""){print $0 new}

instead of the briefer:

sub(/"my_id":.*/,new)

so it won't break if the new string contains any backreference chars such as &.

CodePudding user response:

awk procedure with passed argument for insert value

The following awk procedure allows for 'abcd' to be passed as an argument for insertion (allowing it to be set in a bash script if required).

awk -v insertVal="abcd" '/"my_id":/{$0=$0"\n    \"my_value\": \""insertVal"\","} {print}' dat.txt

explanation

The required insertion string ('abcd' in this case) is passed as an argument using the -v variable switch followed by a variable name and value: insertVal="abcd".

The first awk action block has a pattern condition to only act on lines containing the target-line string (in this case "my_id":). When a line with that pattern is found, the line is extended with a new line mark \n, the required four spaces to start the next line, the specified key named "my_value", and the value associated with the key, passed by argument as the variable named insertVal ("abcd"), and the final , character. Note the need to escape the " quotes to render them.

The final awk block, prints the current line (whether or not it was modified).

test

The procedure was tested on Mac Terminal using GNU Awk 5.2.0.

The output generated (from the input data saved to a file named dat.txt) is:

{
  "id": "a1234567-89ab-cdef-0123-456789abcdef",
  "properties": {
    ...
    "my_id": "c1234567-89ab-cdef-0123-456789abcdef",
    "my_value": "abcd",
    ...
}

CodePudding user response:

Using sed

$ sed -e '/my_id/{p;s/id.*"/value": "abcd"/' -e '}' input_file
{
  "id": "a1234567-89ab-cdef-0123-456789abcdef",
  "properties": {
    ...
    "my_id": "c1234567-89ab-cdef-0123-456789abcdef",
    "my_value": "abcd",
    ...
}

CodePudding user response:

With GNU awk and with your shown samples and attempts please try following awk code.

awk -v newVal='"my_value": "abcd",' -v RS=   'match($0,/(.*)("my_id": "[^"]*",)(.*)/,arr){print arr[1] arr[2] newVal arr[3]}' Input_file
  • Related