1

I want to replace some digit numbers with regex and then do some mathematics by sed, however, my solution lost the original quotation, I already checked the arguments of echo and try with -E but it doesn't work as well, anybody can help?

source file content

cat f1.txt
<AB port="10000" address="0.0.0.0" adpcpu="1"/>

my command

sed -r 's/(.*)(port=\")([0-9]+)(\".*)/echo \"\1\2$((\3+50))\4\"/ge' f1.txt

result

<AB port=10050 address=0.0.0.0 adpcpu=1/>

The resulting content missed the quotation

colin-zhou
  • 185
  • 1
  • 15
  • 1
    [Don't Parse XML/HTML With Regex.](https://stackoverflow.com/a/1732454/3776858) I suggest to use an XML/HTML parser (xmlstarlet, xmllint ...). – Cyrus Jul 30 '21 at 04:11

3 Answers3

2

If you use the p option, you'll see the issue:

$ sed -E 's/(.*)(port=\")([0-9]+)(\".*)/echo \"\1\2$((\3+50))\4\"/gpe' ip.txt
echo "<AB port="$((10000+50))" address="0.0.0.0" adpcpu="1"/>"
<AB port=10050 address=0.0.0.0 adpcpu=1/>

You can workaround by using single quotes:

$ sed -E 's/(.*port=")([0-9]+)(.*)/echo \x27\1\x27$((\2+50))\x27\3\x27/pe' ip.txt
echo '<AB port="'$((10000+50))'" address="0.0.0.0" adpcpu="1"/>'
<AB port="10050" address="0.0.0.0" adpcpu="1"/>

$ sed -E 's/(.*port=")([0-9]+)(.*)/echo \x27\1\x27$((\2+50))\x27\3\x27/e' ip.txt
<AB port="10050" address="0.0.0.0" adpcpu="1"/>

I'll also suggest to use perl instead:

$ perl -pe 's/port="\K\d+/$&+50/e' ip.txt
<AB port="10050" address="0.0.0.0" adpcpu="1"/>
Sundeep
  • 23,246
  • 2
  • 28
  • 103
1

This might work for you (GNU sed):

sed -E '/port="([0-9]+)"/{s//port="$((\1+50))"/;s/"/\\&/g;s/.*/echo "&"/e}' file

It is worth remembering that when the e flag is used in conjunction with the substitution command in sed, the whole of the pattern space is evaluated. Thus in order to use the echo command to interpolate the shell arithmetic, any double quotes in the pattern space must first be quoted/escaped (s/"/\\&/g) and then the idiom echo "pattern space" used. As this results in a chain of commands, braces must be used to group the commands.

N.B. The empty regular expression // repeats the last regular expression match (the same holds if the empty regular expression is passed to the s command).

potong
  • 55,640
  • 6
  • 51
  • 83
0

Using awk, instead of sed:

$ awk -F'"' '{$2 += 50; print}' OFS='"' f1.txt
<AB port="10050" address="0.0.0.0" adpcpu="1"/>

Use " as a field separator for the input (-F'"') and the output (OFS='"'). Add 50 to the second field and print the result.

If your file contains other types of lines and you want to apply the transformation only to the lines that match a pattern, you can be more specific. Fort instance, if the pattern to search for is port=:

$ awk -F'"' '/port=/{$2 += 50} {print}' OFS='"' f1.txt
A line of a different type
<AB port="10050" address="0.0.0.0" adpcpu="1"/>
Another line of a different type
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51