1

I want to insert a new line before the last occurrence of brace. My text file looks like that

 "accounts": {
    "0x0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": "0x0", "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
    "0x00Ea169ce7e0992960D3BdE6F5D539C955316432": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
 }

So what I want to do is adding a new account through sed script.

Please note that the new account will be specified with a variable, something like:

"$ACCOUNT_ADDR": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }

3 Answers 3

1

sed is the wrong tool for this job. One of the right tools is jq.

% cat wibble.json
{
"accounts": {
    "0x0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": "0x0", "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
    "0x00Ea169ce7e0992960D3BdE6F5D539C955316432": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
}
}
% ACCOUNT_ADDR="0xdeadbeeffeefdface0badd00dcacad0d0eeeeeeee"
% jq '."accounts"."'"${ACCOUNT_ADDR}"'"."balance"="42"' wibble.json
{
  "accounts": {
    "0x0000000000000000000000000000000000000008": {
      "builtin": {
        "name": "alt_bn128_pairing",
        "activate_at": "0x0",
        "pricing": {
          "alt_bn128_pairing": {
            "base": 100000,
            "pair": 80000
          }
        }
      }
    },
    "0x00Ea169ce7e0992960D3BdE6F5D539C955316432": {
      "balance": "1606938044258990275541962092341162602522202993782792835301376"
    },
    "0xdeadbeeffeefdface0badd00dcacad0d0eeeeeeee": {
      "balance": "42"
    }
  }
}
%

It also caught the fact that you had a key+value pair with no enclosing object. ☺

3
0

You could add a line after the occurence of "accounts",

sed "/accounts/ a\
  \"$ACCOUNT_ADDR\": { \"balance\": \"1606938044258990275541962092341162602522202993782792835301376i\" }
" file

(The " are escaped, to insert variable)

sed "s/^ }$/ \"$ACCOUNT_ADDR\": { \"balance\": \"1606938044258990275541962092341162602522202993782792835301376i\" }\n }/g" file

Will replace your } line and print two lines.

Run sed -i ... for changing the file, in cycle:

$  cat file
"accounts": {
    "0x0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": "0x0", "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
    "0x00Ea169ce7e0992960D3BdE6F5D539C955316432": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
 }

$ cat script.sh
#!/bin/bash

for i in $(seq 1 5); do
  ACCOUNT_ADDR="account_"$i
  sed -i "/accounts/ a\
      \"$ACCOUNT_ADDR\": { \"balance\": \"1606938044258990275541962092341162602522202993782792835301376i\" }
  " file
done

$ ./script.sh
$ cat file
"accounts": {
"account_5": { "balance": "1606938044258990275541962092341162602522202993782792835301376i" }
"account_4": { "balance": "1606938044258990275541962092341162602522202993782792835301376i" }
"account_3": { "balance": "1606938044258990275541962092341162602522202993782792835301376i" }
"account_2": { "balance": "1606938044258990275541962092341162602522202993782792835301376i" }
"account_1": { "balance": "1606938044258990275541962092341162602522202993782792835301376i" }
    "0x0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": "0x0", "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
    "0x00Ea169ce7e0992960D3BdE6F5D539C955316432": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
 }

2
  • The first solution partially works for me. However, since I need to add more than one address i repeat the command inside a for cycle, in this way I am able to iterate over all the addresses. However, this generates several replicas of the entire json, just updating the first account after the keyword "accounts", and not one unique json with the list of all the accounts. Commented Mar 12, 2019 at 15:49
  • I see, just run sed -i instead of just sed , see my edited answer. Commented Mar 13, 2019 at 6:50
0

Every now and and then I like a sed challenge: using ACCOUNT_ADDR=1234:

sed -n -e '
    x
    $ i\
"'"$ACCOUNT_ADDR"'": {"balance":0},
    2,$ p
    $ { x; p }
' file
 "accounts": {
    "0x0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": "0x0", "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
"1234": {"balance":0},
    "0x00Ea169ce7e0992960D3BdE6F5D539C955316432": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
 }

This uses the x to stash the current line into the hold space to become the "previous" line in the next cycle.

As mentioned elsewhere, use sed -i to save the edits in-place


You can get the same result by reversing the file and using a simpler sed command:

temp=$(mktemp)
tac file | sed '2a\
"'"$ACCOUNT_ADDR"'": {"balance":0},
' | tac > "$temp" && mv "$temp" file

You must log in to answer this question.

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