I have the following json input
... "somefield":"somevalue", "time":"timevalue", "anotherfield":"value" ...
inside my ksh script I wish to replace timevalue with my value. So I created this regular expression using groups with works just fine
data=`cat somefile.json`
echo $data | perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\1%TIME%\2|g" | another-script.sh
... "somefield":"somevalue", "time":"%TIME%", "anotherfield":"value" ...
However ... I cannot use number as substitution because perl uses numbers to define groups .. so this one obviously doen't work
perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\120:00:00\2|g"
I can overcome this by doing two step substitution
perl -pe "s|(.*time\"\s*\:\s*\").*?(\".*)|\1%TIME%\2|g" | perl -pe "s|%TIME%|20:00:00|"
... "somefield":"somevalue", "time":"20:00:00", "anotherfield":"value" ...
but I am sure there is a better and more elegant way doing it
Whilst you could do this with regexes, it would be so much easier with the right tool
jq '.time="20:00:00"' somefile.json
If you particularly wish to use Perl, the core Perl distribution has included a JSON parser since 2011, so you could do something like:
perl -MJSON::PP=decode_json,encode_json -0 -E '$j = decode_json(<>); $j->{time} = "20:00:00"; say encode_json($j)' somefile.json
Perl doesn't use \\1
for substitution. If you had enabled warnings (eg with perl -w
), perl would have told you it's $1
. Which can be disambiguated from surrounding digits by adding {
}
:
perl -pe 's|(.*time"\s*:\s*").*?(".*)|${1}20:00:00$2|g'
(I also removed all the redundant backslashes from the regex.)
On another note, what's the point of matching .*
if you're just going to replace it by itself? Couldn't it just be
perl -pe 's|(time"\s*:\s*").*?(")|${1}20:00:00$2|g'
?
I'm not a big fan of .*
or .*?
. If you're trying to match the inside of a quoted string, it would be better to be specific:
perl -pe 's|(time"\s*:\s*")[^"]*(")|${1}20:00:00$2|g'
We're not trying to validate the input string, so now there's really no reason to match that final "
(and replace it by itself) either:
perl -pe 's|(time"\s*:\s*")[^"]*|${1}20:00:00|g'
If your perl is not ancient (5.10+), you can use \\K
to "keep" leading parts of the string, ie not include it in the match:
perl -pe 's|time"\s*:\s*"\K[^"]*|20:00:00|g'
Now only the [^"]*
part will be substituted, saving us from having to do any capturing.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.