user2519184
user2519184

Reputation: 67

sed doesn't replace variable

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

Answers (2)

diginoise
diginoise

Reputation: 7630

you need matching on exact string

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.

when I thought matching was on the pattern rather than exact string

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

KamilCuk
KamilCuk

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

Related Questions