Reputation: 67
I'm trying to replace some regex line in a apache file. i define:
OLD1="[0-9]*.[0-9]+"
NEW1="[a-z]*.[0-9]"
when i'm executing:
sed -i 's/$OLD1/$NEW1/g' demo.conf
there's no change.
This is what i tried to do
sed -i "s/${OLD1}/${NEW1}/g" 001-kms.conf
sed -i "s/"$OLD1"/"$NEW1"/g" 001-kms.conf
sed -i "s~${OLD1}~${NEW1}~g" 001-kms.conf
i'm expecting that the new file will replace $OLD1 with $NEW1
Upvotes: 0
Views: 255
Reputation: 7630
You would need something that can match on exact string [0-9]*.[0-9]+
which sed
does not support well.
Therefore instead I am using this pipeline replacing one character at a time
(it also is easier to read I think):echo "[0-9]*.[0-9]+" | sed 's/0/a/' | sed 's/9/z/' | sed 's/+//'
You would have to cat
your files or use find
with execute to then apply this pipe.
I had tried following (from other SO answers):
- sed 's/\<exact_string/>/replacement/'
doesn't work as \<
and \>
are left and right word boundaries respectively.
- sed 's/(CB)?exact_string/replacement/'
found in one answer but nowhere in documentation
I used Win 10 bash, git bash, and online Linux tools with the same results.
Replacement cannot be a regex - at most it can reference parts of the regex expression which matched. From man sed
:
s/regexp/replacement/
Attempt to match regexp against the pattern space. If successful, replace that portion matched with replacement. The replacement may contain the special character & to refer to that portion of the pattern space which matched, and the special escapes \1 through \9 to refer to the corresponding matching sub-expressions in the regexp.
Additionally you have to escape some characters in your regex (specifically .
and +
) unless you add option -E
for extended regex as per comment under your question.
(N.B. only if you want to match on the full-stop .
rather than it meaning any character
)
$ echo "01.234--ZZZ" | sed 's/[0-9]*\.[0-9]\+/REPLACEMENT/g'
REPLACEMENT--ZZZ
Upvotes: 3
Reputation: 142005
OLD1="[0-9]*.[0-9]+"
Because the [
*
.
are all characters with special meaning in sed, we need to escape them. For such simple case something like this could work:
OLD2=$(<<<"$OLD1" sed 's/[][\*\.]/\\&/g')
It will set OLD2
to \[0-9\]\*\.\[0-9\]+
. Note that it doesn't handle all the possible cases, like OLD1='\.\['
will convert to OLD2='\\.\\[
which means something different. Implementing a proper regex to properly escape, well, other regex I leave as an exercise to others.
Now you can:
sed "s/$OLD2/$NEW1/g"
Tested with:
OLD1="[0-9]*.[0-9]+"
NEW1="[a-z]*.[0-9]"
sed "s/$(sed 's/[][\*\.]/\\&/g' <<<"$OLD1")/$NEW1/g" <<<'XYZ="[0-9]*.[0-9]+"'
will output:
XYZ="[a-z]*.[0-9]"
Upvotes: 3