joseLuís joseLuís - 10 months ago 90
Bash Question

Sed/Awk replace complex string containing any possible printable character

I need to replace a complex string that can contain any printable characters. This is a real example that I've been unable to replace.

<!-- %cmd: for F in $(find ../[09]* -maxdepth 1 -type d -printf "%P\n" ) | grep -v "^$"; do echo "<li><a href=\"$F\">$F</a></li>"; done -->

I'm even using a non-printable sed delimiter in order to avoid conflicts since the original string should be composed only of printable characters:

DELIM=$(echo -en "\001");

But it doesn't work. I've tried many things, and I can't figure out what I'm missing. E.g.:


UPDATE-1: Current solution by @anubhava works, but doesn't print the non-matched lines. Here is a complete example of the real need: An temporary hack involves using
to replace newlines before and after awk substitution.

Answer Source

You can use conrol characters in sed's delimiter like this:

echo "before $pattern after" | sed "s${delim}${pattern}${delim}newtext${delim}"

before newtext after


As your pattern contain all sorts of special meta characters, it is better to ditch regex (sed) and use non-regex replacement using awk:

pattern='<!-- %cmd: for F in $(find ../[09]* -maxdepth 1 -type d -printf "%P\n" ) | grep -v "^$"; do echo "<li><a href=\"$F\">$F</a></li>"; done -->'

awk -v repl="newtext" 'FNR==NR {
    a = a $0; next
n = index($0, a) {
    print substr($0, 1, n-1) repl substr($0, n+length(a))
}' <(printf "%s\n" "$pattern") <(echo "before $pattern after")

before newtext after

Code Demo