joseLuís joseLuís - 5 days ago 6
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.:

echo "BEFORE $PATTERN AFTER" | sed -e "s${DELIM}${PATTERN}${DELIM}NEWTEXT${DELIM}"





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

Answer

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

pattern='foobar'
delim=$'\01'
echo "before $pattern after" | sed "s${delim}${pattern}${delim}newtext${delim}"

before newtext after

Update:

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

Comments