regex in sed to replace particular string

Viewed 88

I have a file config.txt which consist of lines like below

$ cat config.txt | head -n 3
f03889d9abcb6a16155411bb8e0a34dddb5c8e4c@192.168.3.4:26601
be9d757acee1f5b573ec18d1e056542bc282be23@169.172.56.77:26604
d40ec20a080468fcd5965493d904e4d536cf5767@10.129.101.3:26607

$ cat ip.txt | head -n 3
10.0.4.5
10.3.5.6
10.3.5.8

I would like to replace the IP address on config.txt with ip's on ip.txt file respectively

the expected output is

f03889d9abcb6a16155411bb8e0a34dddb5c8e4c@10.0.4.5:26601
be9d757acee1f5b573ec18d1e056542bc282be23@10.3.5.6:26604
d40ec20a080468fcd5965493d904e4d536cf5767@10.3.5.8:26607

Since the ip's in config file are dynamic, I need to use regex in sed to replace the IP. for an example:

$ echo "f03889d9abcb6a16155411bb8e0a34dddb5c8e4c@192.168.3.4:26601" | sed "s/*@\+:*/*@10.0.4.5:*/g"

but its not updating the ip's. I am very new to the regex in scripting. Kindly help!

5 Answers

Well, in this case it is possible to use sed and a regex. You could first join the files and then use regex to shuffle lines:

paste config.txt ip.txt | sed 's/@[^:]*\(.*\)\t\(.*\)/@\2\1/'

Note that sed works in the context of a single line only. But a regex is not "dynamic", if the ip's in config file are dynamic then you should use something "more" then regex, better a full programming language with support for maps and internal state, like awk but also perl or python.

A way using awk instead. It first reads ip.txt and stores its contents in an array indexed by line number, and then for each line of config.txt, replaces the IP address in it with the one from the corresponding line of ip.txt:

$ awk 'FNR==NR { ips[FNR] = $0; next }
       { sub(/@[^:]+:/, "@" ips[FNR] ":"); print }' ip.txt config.txt
f03889d9abcb6a16155411bb8e0a34dddb5c8e4c@10.0.4.5:26601
be9d757acee1f5b573ec18d1e056542bc282be23@10.3.5.6:26604
d40ec20a080468fcd5965493d904e4d536cf5767@10.3.5.8:26607

Another way:

paste -d~ config.txt ip.txt | while IFS="~" read config ip; 
do
echo $config | sed -r "s/([a-z0-9]+)@(([0-9]{1,3}\.?){4})(:[0-9]+)/\1@$ip\4/g";
done;

Here's a pure sed answer. I commented it. Put the content to my.sed and call sed -n -f my.sed config.txt ip.txt

# We concat config.txt and ip.txt to a single line like
# f...c@192.168.3.4:26601|b...3@169.172.56.77:26604|d...7@10.129.101.3:26607|;10.0.4.5;10.3.5.6;10.3.5.8
# the characters "|" and ";" are used as separators
# the records of config.txt are identified by @,
# those of ip.txt the pattern ^[0-9]\(\.[0-9]\)\{3\}

# if it's a config.txt line append "|" and append it to the hold space
/@/ {
    s/$/|/
    H
}
# if it's a ip.txt line put a ";" before it and append it to the hold space
/^[0-9]\+\(\.[0-9]\+\)\{3\}/ {
    s/^/;/
    H
}
# Now the two files are read. We do the replacements at the end of input
$ { 
    x
    # after having deleted all newlines the pattern spaces consists
    # of one line as mentioned above
    s/\n//g
    :b
    # now we replace recursively the ip adress in the first "|"
    # limited column by the ip adress in
    # the first ";" limited column. (:b ist the beginning of the loop) 
    # 1. group: sequence of not | characters ended by @<ip-adress>:<not | characters>
    # 2. group: the characters including the "@"
    # 3. group: part of the ip adress pattern
    # 4. group: the characters from : to "|" (excluded)
    # 5. group: the sequence of not ";" characters followed by ";"
    # 6. group: the replacement ip adress
    # 7. group: part of the replacement ip adress pattern
    # The "," in the replacement replaces the first "|" in order
    # to enable recursion (see 1. group above)

    s/\(\([^|]*@\)[0-9]\+\(\.[0-9]\+\)\{3\}\(:[^|]*\)\)|\([^;]*\);\([0-9]\+\(\.[0-9]\+\)\{3\}\)/\2\6\4,\5/
    tb
    # replace all , except the last one with newlines
    s/,\(.\)/\n\1/g
    # replace the last ","
    s/,//
    p
}

This might work for you (GNU sed & cat):

cat -n ipFile | sed -E 's/\t(.*)/s#@.*:#@\1:#/' | sed -f - configFile

Prepend line numbers to the ipFile.

Replace each line in the ipFile by a sed substitution command for an ip address.

Invoke a second application of sed using the configFile as the source and apply the substitution command from the ipFile against each line in the file.

N.B. The -f option accepts sed command from a file, in this cast the file is - piped through from the previous application of sed.


Another solution:

paste configFile ipFile | sed -E 's/@.*:(\S*)\t(\S+)/@\2:\1/;/@/!d'

This will replace the appended ip address in the configFile.

N.B. If the ipFile has more lines than the configFile the /@/!d will make sure the additional lines are not included.

Related