This is what I came up with but it doesn't work with multiple lines:

sed -i '/<!-- my comment -->.*<!-- \/my comment end -->/d' my_file


1 Answer 1


Since sed in its default mode operates on a line-by-line basis, an (admittedly obfuscated) approach would be to replace the newline characters with something else (such as the NULL character \x00) before feeding the the content into sed:

tr '\n' '\x00' <my_file

sed then sees the content as one line. However,

sed -e 's/<!-- my comment -->.*<!-- \/my comment end -->//'

will not work due to the greedy matching nature of sed. We could implement a non-greedy match by matching everything inside the comment up to the first < character, but this would work only if HTML comments were not allowed to contain < characters (and, in particular, other HTML tags), which we cannot assume.

To solve this, we'll convert the sequence <! to a single character not used elsewhere in the file, for which we can construct a non-greedy match. We'll choose the special character \x01 for this purpose, which we convert back to <! after the non-greedy match:

sed -e $'s/<!/\x01/g' -e $'s/\x01-- my comment -->[^\x01]*\x01-- \/my comment end -->//g'

(note the use of the shell syntax $'' instead of '' to pass the literal single-byte character \x01 to sed)

In a third stage, the NULL characters are converted back into newlines:

tr '\x00' '\n'

And finally, empty lines are suppressed by another invocation of sed:

sed -e '/^$/d'

In summary,

tr '\n' '\x00' <my_file |sed -e $'s/<!/\x01/g' -e $'s/\x01-- my comment -->[^\x01]*\x01-- \/my comment end -->//g' |tr '\x00' '\n'|sed -e '/^$/d'

More elegant solutions exist if you choose to use different tools (awk or perl one-liners) instead of sed, such as:

perl -0pe 's/<!-- my comment -->.*?<!-- \/my comment end -->//gs' my_file

  • I changed my suggested answer to work around this.
    – Guido
    Mar 28, 2016 at 4:48

You must log in to answer this question.

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