I have a file foo.properties with contents like
foo=bar
# another property
test=true
allNames=alpha:.02,beta:0.25,ph:0.03,delta:1.0,gamma:.5
In my script, I need to replace whatever value is against ph
(The current value is unknown to the bash script) and change it to 0.5. So the the file should look like
foo=bar
# another property
test=true
allNames=alpha:.02,beta:0.25,ph:0.5,delta:1.0,gamma:.5
I know it can be easily done if the current value is known by using
sed "s/\,ph\:0.03\,/\,ph\:0.5\,/" foo.properties
But in my case, I have to actually read the contents against allNames
and search for the value and then replace within a for loop. Rest all is taken care of but I can't figure out the sed
/perl
command for this.
I tried using sed "s/\,ph\:.*\,/\,ph\:0.5\,/" foo.properties
and some variations but it didn't work.
CodePudding user response:
With your shown samples, please try following awk
code.
awk -v new_val="0.5" '
match($0,/,ph:[0-9] (\.[0-9] )?/){
val=substr($0,RSTART 1,RLENGTH-1)
sub(/:.*/,":",val)
print substr($0,1,RSTART) val new_val substr($0,RSTART RLENGTH)
next
}
1
' Input_file
Detailed Explanation: Creating awk
's variable named new_val
which contains new value which needs to put in. In main program of awk
using match
function of awk
to match ,ph:[0-9] (\.[0-9] )?
regex in each line, if a match of regex is found then storing that matched value into variable val
. Then substituting everything from :
to till end of value in val variable with :
here. Then printing values as pre requirement of OP(values before matched regex value with val(edited matched value in regex) with new value and rest of line), using next will avoid going further and by mentioning 1
printing rest other lines which are NOT having a matched value in it.
2nd solution: Using sub
function of awk
.
awk -v newVal="0.5" '/^allNames=/{sub(/,ph:[^,]*/,",ph:"newVal)} 1' Input_file
CodePudding user response:
Would you please try a perl
solution:
perl -pe '
s/(?<=\bph:)[\d.] (?=,|$)/0.5/;
' foo.properties
- The
-pe
option makesperl
to read the input line by line, perform the operation, then print it assed
does. - The regex
(?<=\bph:)
is a zero-length lookbehind which matches the stringph:
preceded by a word boundary. - The regex
[\d.]
will match a decimal number. - The regex
(?=,|$)
is a zero-length lookahead which matches a comma or the end of the string. - As the lookbehind and the lookahead has zero length, they are not
substituted by the
s/../../
operator.
[Edit]
As Dave Cross comments, the lookahead (?=,|$)
is unnecessary as long as the input file is correctly formatted.
CodePudding user response:
Works with decimal place or not, or no value, anywhere in the line.
sed -E 's/(^|[^-_[:alnum:]])ph:[0-9]*(.[0-9] )?/ph:0.5/g'
Or possibly:
sed -E 's/(^|[=,[:space:]])ph:[0-9] (.[0-9] )?/ph:0.5/g'
The top one uses "not other naming characters" to describe the character immediately before a name, the bottom one uses delimiter characters (you could add more characters to either). The purpose is to avoid clashing with other_ph
or autograph
.
CodePudding user response:
Here you go
#!/usr/bin/perl
use strict;
use warnings;
print "\nPerl Starting ... \n\n";
while (my $recordLine =<DATA>)
{
chomp($recordLine);
if (index($recordLine, "ph:") != -1)
{
$recordLine =~ s/ph:.*?,/ph:0.5,/g;
print "recordLine: $recordLine ...\n";
}
}
print "\nPerl End ... \n\n";
__DATA__
foo=bar
# another property
test=true
allNames=alpha:.02,beta:0.25,ph:0.03,delta:1.0,gamma:.5
output:
Perl Starting ...
recordLine: allNames=alpha:.02,beta:0.25,ph:0.5,delta:1.0,gamma:.5 ...
Perl End ...
CodePudding user response:
A simpler sed solution:
sed -E 's/([=,]ph:)[0-9.] /\10.5/g' file
foo=bar
# another property
test=true
allNames=alpha:.02,beta:0.25,ph:0.5,delta:1.0,gamma:.5
Here we match ([=,]ph:)
(i.e. ,
or =
followed by ph:
) and capture in group #1. This should be followed by 1 of [0-9.]
character to natch any number. In replacement we put \1
back with 0.5