1

How to translate from moderen editor regex to sed syntax?

Seasoned developer, but complete sed noob here, thank you for looking.

  • Working on Pop OS Linux 20.04 LTS
  • I "cook up" my regular expressions in VS Code as it matches real-time as you key in patterns, very handy!
  • Attempting to edit an XML with sed in my Dockerfile.
  • I have my pattern matching in VS Code, but for the life of me can't seem to find the right sed command syntax.
  • Rewritten my regex 3 different ways, process of elimination isn't working. Cannot find what concept/syntax I'm missing here.

XML Before

<!-- HTTP Connector from upstream proxy -->
<Connector executor="tomcatConnectorThreadPool" port="8081" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
            connectionTimeout="3000" enableLookups="false" redirectPort="443" URIEncoding="UTF-8" bindOnInit="false"
            scheme="http" proxyPort="80" />

XML After (What I'm going after)

<!-- HTTP Connector from upstream proxy -->Hello World

My Regex that works in VS Code

Search Pattern

(<!-- HTTP Connector from upstream proxy -->)(^.*)(^.*)(^.*)

Replace Pattern

VS Code back-reference = $1

$1Hello World

sed failures

Guessing why these don't work.

  1. Sorta hairy regex, can't interpret special characters?

    sed -E 's/(<!-- HTTP Connector from upstream proxy -->\n)([<.\w="\-\s\/>]*$)/\1Hello World/g' path/to/xml.xml
    
  2. Sub-sub references aren't legal?

    sed -E 's/(<!-- HTTP Connector from upstream proxy -->\n)((^.*\n){3})/\1Hello World/g' path/to/xml.xml
    
  3. Not sure why this doesn't work?

    sed -E 's/(<!-- HTTP Connector from upstream proxy -->)\n(^.*)\n(^.*)\n(^.*)/\1Hello World/g' path/to/xml.xml
    

How to express these regular expressions in to proper sed command syntax?

0

1 Answer 1

0

The problem is that you seem to be attempting to match across multiple newlines. Your regex:

(<!-- HTTP Connector from upstream proxy -->)(^.*)(^.*)(^.*)

This isn't something that would work in any of the regular expression flavors I know. Your VSCode tool seems to be using a regex flavor where multiple ^ implicitly mean "match across newlines". Most *nix utilities work on "records" (lines) defined by a trailing \n character. You need tricks to get them to match across multiple lines.

Since you are on Linux, which means you have GNU sed, you could do this:

$ sed -Ez 's/^(<!-- HTTP Connector from upstream proxy -->)\n([^\n]*\n){3}/\1Hello World\n/' file.xml 
<!-- HTTP Connector from upstream proxy -->Hello World

Or, in your case, the much shorter:

$ sed -Ez 's/^(<!--[^\n]*)\n([^\n]*\n){3}/\1Hello World\n/' file.xml 
<!-- HTTP Connector from upstream proxy -->Hello World

The trick here is the -z which makes sed slurp the entire file and treat it as one "record". Then, we tell it to find a <!-- at the beginning of the record and capture that as \1 (you need parentheses to capture groups), and then match the longest stretch of non-newline characters until a newline ([^\n]*\n) and then three more lines (lines means non-newline characters followed by a newline: ([^\n]*\n){3}).

For this task, I wouldn't use a regex at all, just use the line numbers:

$ sed '1s/$/Hello world!/; 2d;3d;4d' file.xml 
<!-- HTTP Connector from upstream proxy -->Hello world!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .