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
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!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.