使用sed修改XML文件端口失败原因排查及有效命令分享
sed Command Failed (And the Fix Explained) Let's break down exactly why your first sed command didn't make any changes, then walk through why the working command you found gets the job done right.
Issues with the Original sed Command
Your initial attempt was:
sed "s|\(\"^[[:space:]]*.+port[[:space:]]+protocol=.+port=\"\).*|\1\"3022\"/>|" inputfile
Here's what went wrong:
No
-Eflag for Extended Regular Expressions (ERE)
By default,seduses Basic Regular Expressions (BRE), where syntax like.+(one or more of any character) and+(repetition) isn't recognized. Yourgrep -Eworked because-Eenables ERE—but yoursedcommand skipped this flag, so the regex couldn't match your target line at all.Invalid leading quote in the capture group
Your capture group starts with\"^[[:space:]]*—that leading quote doesn't exist in your target line (<port protocol="tcp" port="22"/>starts with<, not a quote). This broke the match before it even got started.Overcomplicated and misaligned capture group logic
Even if you fixed the above issues, the regex was overengineering the pattern match. It tried to wrap a chunk of the line that doesn't align with the actual structure of your XML, making it impossible to correctly target theport="22"segment you wanted to change.
Why the Working sed Command Works
The command you discovered hits all the right marks:
sed -E '/short/,/service/ s/port=[^<]*/port=\"3022\"/>/' inputfile
Let's unpack it:
-Eenables ERE
This lets you use the same flexible regex syntax that made yourgrep -Esuccessful, avoiding the limitations of BRE.Address range:
/short/,/service/
This targets only the lines between (and including) the line with<short>SSH</short>and the closing</service>tag. This ensures you only modify the SSH service's port, not any other service entries if your XML file had multiple.Substitution pattern:
s/port=[^<]*/port=\"3022\"/>/port=[^<]*matchesport=followed by any characters except<—since your line ends with/>, this grabs exactly theport="22"segment you want to replace.- It swaps that matched text with
port="3022"/>, cleanly updating the port number while keeping the rest of the line's structure intact.
内容的提问来源于stack exchange,提问作者Chris

