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" }
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. ☺

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" }
 }

  • 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. – Stefano De Angelis Mar 12 at 15:49
  • I see, just run sed -i instead of just sed , see my edited answer. – ILikeMatDotH Mar 13 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.