Andrew Newby
Andrew Newby

Reputation: 5206

How to escape dots in variable using bash, and replacing value in file?

I'm trying to work out how to edit a file in a bash script, and replace it with a variable with the dots escaped. For example 123.123.123.123 needs to be replaced in the file jail.local, as 123\.123\.123\.123. I found some posts on SO that gave me some ideas, but I just can't get it right:

#!/bin/bash

admin_host="admin.foo.com"

server_ip_4=$(hostname -I | awk '{print $1}')
server_ip_4_escaped=$(hostname -I | awk '{print $1}' | sed "s/\./\\\./g")

echo "TEST: $server_ip_4_escaped , $server_ip_4"

sed -i "s/IP_v4/$(echo $server_ip_4_escaped)/" /etc/fail2ban/filter.d/maltrail.conf

prints out:

sh install-maltrail.sh
Please type your admin URL - i.e admin.foobar.com and press [ENTER]
TEST: 213\.219\.38\.123 , 213.219.38.123

But when I look at maltrail.conf, it has:

failregex = ^.*admin.foo.com <HOST> \d+ 213.219.38.44 .*(attacker|scanner|reputation).*

when I need:

failregex = ^.*admin\.foo\.com <HOST> \d+ 213\.219\.38\.44 .*(attacker|scanner|reputation).*

Upvotes: 0

Views: 197

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84599

With a little more fiddling we can replace the '.' with both digits with word characters and have it work with your example. For instance:

sed 's/[.]\(\(\w\w*\)\|\([0-9]\{1,3\}\)\)/\\.\1/g' file

Which essentially finds a '.' followed by any word character \w (at least 1) written as \w\w* OR conditionally a '.' followed by 1-3 digits [0-9]\{1,3\}. Both expressions are captured conditionally in \(\(words\)\|\(digits\)\) and then the global replacement made.

Example Use/Output

$ echo "failregex = ^.*admin.foo.com <HOST> \d+ 213.219.38.44 .*(attacker|scanner|reputation).*" |
sed 's/[.]\(\(\w\w*\)\|\([0-9]\{1,3\}\)\)/\\.\1/g'
failregex = ^.*admin\.foo\.com <HOST> \d+ 213\.219\.38\.44 .*(attacker|scanner|reputation).*

Which appears to be what you are looking for.

If you have extended REGEX available, generally through the -E (or -r) option to sed, you can cut down on the escapes in the expression. For example:

sed -E 's/[.]((\w+)|([0-9]{1,3}))/\\.\1/g'

It works the same, but there were some implementations in the past (I think on Mac) that didn't have ERE available.

Upvotes: 2

Related Questions