In a text file test.txt are many lines of text, of which I want to extract a single line matching:
blabla 28.40.00 blabla
I would like to replace the first digit of the middle number (in this case 4) by three. That is, no matter what the middle number is (40, 41, 52, 63 etc), I would like it to be replaced by a number starting with 3 (40 becomes 30, 41 becomes 31, 52 becomes 32, 63 becomes 33 etc).
The following line matches the middle number and replaces it with the alphabet a
:
cat test.txt |awk '/blabla/'|sed -E s_[[:digit:]][[:digit:]]_3_2
output: blabla 28.3.00 blabla
But when I want to replace only the first digit, sed doesn't work:
cat test.txt |awk '/blabla/'|sed -E s_[[:digit:]]\([[:digit:]]\)1_3\1_2
output: blabla 28.40.00 blabla
What am I doing wrong?
CodePudding user response:
To always replace the third digit in the line:
$ echo 'blabla 28.40.00 blabla' | sed 's/[0-9]/3/3'
blabla 28.30.00 blabla
If the number before the .
can have more than 2 digits, here's one workaround:
$ echo 'blabla 528.40.00 blabla' | sed 's/\.[0-9]/.3/'
blabla 528.30.00 blabla
In your second attempt, you should quote the command and use unescaped parenthesis. You also seem to have an extra 1
after the capture group.
$ echo 'blabla 28.40.00 blabla' | sed -E 's_[[:digit:]]([[:digit:]])_3\1_2'
blabla 28.30.00 blabla
Also, you don't need awk
in this case. You can add filter in sed
as well:
$ echo 'blabla 28.40.00 blabla' | sed -E '/blabla/ s_[[:digit:]]([[:digit:]])_3\1_2'
blabla 28.30.00 blabla
CodePudding user response:
This will match the two digits between '.' and replace the first digit with a 3.
echo blabla 28.40.00 blabla | sed -n '/blabla/s/\.[0-9]\([0-9]\)\./.3\1./p'
returns
blabla 28.30.00 blabla
CodePudding user response:
I think the main problem is the stray 1
in the expression (right before _3
). Try:
sed -E 's@[[:digit:]]([[:digit:]])@3\1@2'
But sed
seems awkward for this. What do you want to do with 3 digit numbers? Assuming you want to change 129 to 39, you might prefer the less awkward:
echo 'blabla 28.129.00 blabla' | awk '/blabla/{$2 = 30 $2 % 10}1' FS=. OFS=.
(This will change whitespace in the line and you need to worry about how to deal with lines in which "blabla" contains a .
, but the question doesn't really give enough information to know how to handle those situations. A similar issue occurs with sed
solutions if blahblah
contains pairs of digits.)
CodePudding user response:
First of all cat
is unnecessary as awk/sed
can directly operate on a file.
Secondly since you are already using awk
, you can do this job in awk
itself without doing awk | sed
.
Consider this gnu-awk
solution:
awk '/blabla/ {
$0 = gensub(/([^0-9]*[0-9] \.)[0-9]/, "\\13", "1")
} 1' test.txt
blabla 28.30.00 blabla
This gensub
function matches 0 or more non-digits followed 1 digits and following dot in a capture group. Finally we match a digit that we want to replace. In the replacement we substitute original captured value back using \\1
followed by the new digit we want i.e. 3
.
CodePudding user response:
As you have many lines and you want to replace the first digit of the middle number, you can match that format of numbers with 2 dots in between.
Use the 2 capture groups in the replacement \13\2
.
sed -E 's/([0-9]\.)[0-9]([0-9]*\.[0-9])/\13\2/' test.txt
The pattern matches
^
Start of string([0-9]\.)
Capture group 1, match a single digit and a dot[0-9]
Match the single digit (to replace)([0-9]*\.[0-9])
Capture group 2, match optional digits, then.
and a single digit
Output
blabla 28.30.00 blabla