How can I add a property in the end of the object (text manipulation)
I’m doing some text manipulation and I want to add a property (at the end) to an object named "object" that is inside a configuration file
e.g
.
.
object = {
"one": "one",
"two": "two",
}
.
.
Should become
.
.
object = {
"one": "one",
"two": "two",
"three": "three",
}
.
.
This is my attempt, but i’m wondering if there is a cleaner way of doing things.
#find line for last property
line=$(grep -n "$(awk "/object/{f=1;next} /}/{f=0} f" file.txt | tail -n 1)" file.txt | awk -F : '{ print $1 }')
content='"three" = "three"'
awk 'NR=='$((line + 1))' {print "t '"$content"'"} 1' file.txt > file.temp && mv file.temp file.txt
Using any awk:
$ content='"three" = "three"'
$ awk -v content="$content" '
/^object = {/ { f=1 }
f && /^}/ { print " " content; f=0 }
{ print }
' file
.
.
object = {
"one": "one",
"two": "two",
"three": "three",
}
.
.
Kinda cumbersome (as most Perl code, and by the moment I realized I was too invested to scrap the thing anyways), but it should be a fair attempt at parsing and modifying the right hand side of the option
assignments as pseudo-JSONs in a proper manner, using Perl’s JSON module (on Debian-based distros you could install the module via sudo apt install libjson-perl
, or, of course, on any distro, you could install the module via CPAN).
The code is a bit terse at times, I’ll just give a rough idea of what’s going on.
perl -MJSON -pse '
BEGIN {$/ = "}"}
s
/^(([n]+)?object = )(.*)
/$1 . to_json({ %{ from_json($3, {relaxed => 1}) }, split(/:/, $var) }, {pretty => 1})
/se
' <input -- -var='foo:bar'
Just the Perl code, formatted in a more human-readable manner, with syntax highlighting:
BEGIN {
$/ = "}"
}
s
/^(([n]+)?object = )(.*)
/$1 . to_json(
{
%{ from_json($3, {relaxed => 1}) },
split(/:/, $var)
},
{pretty => 1}
)
/se
This will add a "foo":"bar"
key / value pair to any valid JSON found on the right hand side of an option
assignment found in the input
file:
~ % cat input
object = {
"one": "one",
"two": "two",
}
object = {
"three": "three",
"four": "four",
}
~ % perl -MJSON -pse '
BEGIN {$/ = "}"}
s
/^(([n]+)?object = )(.*)/
$1 . to_json({ %{ from_json($3, {relaxed => 1}) }, split(/:/, $var) }, {pretty => 1})
/se
' <input -- -var='foo:bar'
object = {
"one" : "one",
"two" : "two",
"foo" : "bar"
}
object = {
"four" : "four",
"three" : "three",
"foo" : "bar"
}
I won’t break this down line by line, but the logic is:
- Read in a a string
foo:bar
(which represents the key / value pair to add) and store it into a variablevar
- Read the file using an input record separator of
}
, so to split the file into multiple records delimited by the end of each JSON object - If a record matches an optional sequence of newlines followed by
option =
, treat the rest of the record as a valid "relaxed" JSON object (relaxed as in: commas are allowed after the last element of an object / array, which isn’t strictly valid JSON) - Deserialize the JSON string into a Perl hash, and add the key / value pair resulting from the splitting of
var
on:
- Serialize the hash back into a JSON string, prettifying the output
Caveats:
- If a supplied key already exists in the pseudo-JSON object, its value will be overridden by the supplied value;
- The order of the key / value pairs in the input file won’t necessarily be preserved;
- Likewise, the added key / value pair won’t necessarily end up being the last in the list;
- Despite accepting pseudo-valid JSON objects as the JSON objects to process, this will output only valid JSON objects (i.e. the last key / value pair won’t include a trailing comma)
If it’s to insert "three": "three",
before the first }
line that follows a object = {
line, then that could be:
sed '
/^object = {$/,/^}$/{
/^}$/i
"three": "three",
}'
Or same with awk
:
awk '$0 == "object = {", $0 == "}" {
if ($0 == "}") print " "three": "three""
}
{print}'
Or:
awk '$0 == "object = {", $0 == "}" && $0 = " "three": "three"n" $0 {};1'
Relying on the fact that that $0 = ...
assignment will always return true as guaranteed to be neither the empty string nor any representation of zero.