0

I want to change port in following input file:

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>SSH</short>
  <port protocol="tcp" port="22"/>
</service>

I tried following command without success:

sed "s|\("^[[:space:]]*.+port[[:space:]]+protocol=.+port="\).*|\1\"3022\"\/>|" inputfile

but it does no change.

When I grep -E it return correct line and high-light correct matching:

# grep -E '^[[:space:]]*.+port[[:space:]]+protocol=.+port=' inputfile
  <port protocol="tcp" port="22"/>

Why sed does not do the job?

Update: I found another command to achieve this:

sed -E '/short/,/service/  s/port=[^<]*/port=\"3022\"\/>/' inputfile
Cyrus
  • 84,225
  • 14
  • 89
  • 153
Chris
  • 939
  • 2
  • 11
  • 22
  • Have you tried `sed` with the `-E` flag, like you did with `grep`? – Jaap Joris Vens Dec 19 '20 at 12:33
  • yes, it returns then error "sed: -e expression #1, char 68: invalid reference \1 on `s' command's RHS" – Chris Dec 19 '20 at 12:44
  • 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 Dec 19 '20 at 14:54

1 Answers1

2

Why sed does not do the job?

Because sed regex and grep regex are different, as to which characters you have to escape to get the same meaning. In sed + means literal +, I think you want:

sed 's|\(^[[:space:]]*.\+port[[:space:]]\+protocol=.\+port=\).*|\1"3022"/>|'

whereas in extended POSIX regular expression \( means literal (, wheres ( starts a group:

sed -E 's|(^[[:space:]]*.+port[[:space:]]+protocol=.+port=).*|\1"3022"/>|'

Note I also changed quoting from " to ' for easier escaping.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111