Reputation: 4248
I'm trying to do the following in a bash script to a file:
Before:
{
"main": "3.3.0",
"archive":[
"3.2.2"
]
}
After:
{
"main": "3.3.1",
"archive":[
"3.3.0",
"3.2.2"
]
}
using this perl one liner:
perl -pi -e "s/\"main\"\: \"(.*?)(\".*)\[/\"main\": \"${version}\2\[\n\t\t\"\1\",/s" "$json"
Where $version
holds the new version number and $json
is the path to the file.
It seems perl doesn't match, and I can't understand why. Removing the \[
does match, but I can't see what's wrong with that literal.
Upvotes: 0
Views: 213
Reputation: 13239
Using jq
to both move the main
version number to the array archive
and increment the last digit of the main
version:
jq '.archive += [.main] |
.main |= (split(".") | .[-1] |= (tonumber+1|tostring) | join("."))' file
The operator +=
adds a new value to the array archive
.
The operator |=
assigns a new value to main
. The last element of the splitted string is incremented by 1 and then reassembled.
Upvotes: 1
Reputation: 66873
Assuming that you can fix your JSON (a trailing comma is not allowed) I'd recommend to process this using a module, and in a script.
An example with JSON, wrapped in a "one"-liner as asked
perl -MPath::Tiny -MJSON -0777 -wnE'
my $hr = decode_json $_;
unshift @{$hr->{archive}}, $hr->{main};
$hr->{main} =~ s/[0-9]+\.[0-9]+.\K([0-9]+)/$1+1/e;
path("new_".$ARGV)->spew(encode_json $hr)'
' data.json
The very handy Path::Tiny is used to easily dump JSON output. I make the output file name by prefixing new_
to the input filename (available in $ARGV variable), adjust as suitable.
If installing a module is a problem for some reason you can instead simply print the JSON encoded string and redirect the output
perl -MJSON -0777 -wnE'
my $hr = decode_json $_;
unshift @{$hr->{archive}}, $hr->{main};
$hr->{main} =~ s/[0-9]+\.[0-9]+.\K([0-9]+)/$1+1/e;
say encode_json $hr
' data.json > new_data.json
These produce the output file with   {"archive":["3.3.0","3.2.2"],"main":"3.3.1"}
With the -0777
command switch the whole file is "slurped" into a scalar ($_
) and -M...
loads the given module. Then we use decode_json
, which JSON
exports by default in its functional interface, to obtain a hashref with data.
The current value of main
is then added to the beginning of the arrayref in archive
using unshift, and is then changed by bumping up its release/patch number, using a regex.
Finally the encode_json
, also exported in JSON
's functional interface, is used to JSON-encode the hashref, what is dumped either with Path::Tiny
to a file or to STDOUT for redirection.
A word on the number of existing JSON modules is in order, prompted by comment by Grinnz.
The JSON linked above will load the JSON::XS module, and if that is not installed then it falls back to the compatible pure-Perl one, JSON::PP. I'd recommend the XS module, which is much faster and proven in wide use.
Another option is Cpanel::JSON::XS, the JSON::XS
fork with a bug tracker and a list of bug fixes. I've happily used both without any issues.
To have these tried in order Cpanel::
then ::XS
then ::PP
, also with some improvements over JSON
in how backends are loaded, use JSON::MaybeXS.
Note that none of these are in core.
Upvotes: 3
Reputation: 52336
(now that Ihis question has been reopened and I can post an answer..)
Assuming you fix your data so it's valid JSON (Note the invalid trailing comma), this is an easy jq one-liner:
$ jq "{main: \"$version\", archive: [ .main, .archive[] ]}" "$json" > new.json
$ mv -f new.json "$json"
Just like with HTML and XML, using regular expressions to try to manipulate JSON is a mistake. Use a more appropriate tool.
Upvotes: 1