Match a whole word (IP address) using `sed`

6,998

Solution 1

If you use a modern sed, the following works:

sed -e 's/\(^\|[^0-9]\)1\.2\.3\.4\($\|[^0-9]\)/\1NEWIP\2/'

I.e., replace 1.2.3.4 by NEWIP, if at the beginning of the line or preceded by a non-digit, and if additionally at the end of the line or followed by a non-digit.

With an old sed version that doesn't support extended regexps, it's more complicated. You can do it, e.g., using marking characters. We need two characters that are guaranteed not to occur in the input. In the solution below, I use , and : here, but any other characters will do, even control characters.

sed -e 's/\(1\.2\.3\.4\)/,\1:/;s/\([0-9]\),/\1/;s/:\([0-9]\)/\1/;s/,.*:/NEWIP/;s/[,:]//'

We first insert , before and : after the pattern that we want to replace; then we delete , if preceded by a digit and : if followed by a digit; then we replace the string from , to : (if still present) by the replacement string; finally we delete any remaining , or :.

With perl, one could also use a negative look-ahead assertion (?!\d) and a negative look-behind assertion (?<!\d) to ensure that the pattern only matches if not preceded or followed by a digit:

perl -pe 's/(?<!\d)1\.2\.3\.4(?!\d)/NEWIP/;'

Solution 2

You have not said what you want done with the lines that don't contain a valid IP so I assume you just want to ignore them. Then, all you need to do is make sure the entire line matches three groups of one to three numbers ([0-9]{1,3}), then a final group of one to three numbers. Here are three ways of doing that:

  • GNU sed

    sed -r 's/^([0-9]{1,3}\.){3}[0-9]{1,3}$/5.6.7.8/' file
    
  • Non-GNU sed

    sed  's/^\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}$/5.6.7.8/' file
    
  • Perl

    perl -pe 's/^(\d{1,3}\.){3}\d{1,3}$/5.6.7.8/' file
    
Share:
6,998

Related videos on Youtube

NabilJaran
Author by

NabilJaran

Updated on September 18, 2022

Comments

  • NabilJaran
    NabilJaran over 1 year

    I have the following line style in a file:

    1.2.3.4
    1.2.3.4a
    1.2.3.45
    iaa1.2.3.4ad
    11.2.3.4a
    a1.2.3.4
    1.2.3.4>
    <1.2.3.4>
    <"1.2.3.4">
    1.2.3.4 hostname
    

    I want to replace all the ip '1.2.3.4' with another ip, such as '9.8.7.6', including in <> and in "" and with a letter preceded or followed by the ip.

    But NOT the '11.2.3.4' or the '1.2.3.45'

    So No. 1.2.4.6.7.8.9.10 are both matched.

    Note: '1.2.3.4' is just an example here, It can be any valid ips.

    I want to use sed to replace 1.2.3.4 with another ip.

    I don't know how to write the sed command.

    sed "s/oldip/newip/g"
    

    I know a little about regular expression but this is seems too difficult for me.

    Thank you.

    • Costas
      Costas over 9 years
      sed -E 's/([0-9]{1,3}\.){3}[0-9]/other_ip/'
    • terdon
      terdon over 9 years
      When asking questions like this, please always include your desired output. If you just show your input it is very hard to understand.
  • terdon
    terdon over 9 years
    Neither of these works, they both replace almost everything but miss real IPs. Try it on the OP's file, you'll see things like iaaNEWIPad and aNEWIP. The OP only wants to replace valid IPs. Also, I doubt the actual IPs are 1.2.3.4, that's just an example so you need a solution that works with any numbers.
  • Uwe
    Uwe over 9 years
    @terdon The original question is unclear. Essentially, the OP asks two questions that should have different solutions. After the example, he says that he wants to match No. 1, 2, 4, 6, 7, 8, 9 (where 1.2.3.4 is potentially preceded or followed by a letter), but not 3 and 5 (where 1.2.3.4 is preceded or followed by a number, resulting in a different IP). So it seems that iaaNEWIPad (from No. 4) is indeed an expected result. If not, the OP should make his question more precise.
  • terdon
    terdon over 9 years
    Fair enough, I read through the Q quickly and understood one thing but you're quite right, it can also be interpreted in the way you did. The OP should clarify. Anyway, sorry for the unwarranted (as it turns out) downvote, I made an edit so I could retract it.
  • NabilJaran
    NabilJaran over 9 years
    @terdon I'm sorry, I didn't describe the question clearly, I want to replace the whole '1.2.3.4' with another ip. I will edit the question. Thank you.
  • NabilJaran
    NabilJaran over 9 years
    @Uwe I have updated the question, I hope you can understand me. Thank you.
  • Ludwig Schulze
    Ludwig Schulze over 9 years
    For what OP describes, it is just 4 single numbers separated by a single dot, instead of valid IP's, since he doesn't want the '11.2.3.4' nor '1.2.3.45' replaced.
  • NabilJaran
    NabilJaran over 9 years
    @terdon 1.2.3.4 is only an example, It may be any valid ips.
  • NabilJaran
    NabilJaran over 9 years
    @terdon I'm sorry, but it doesn't work, the ip may be not at the front of the line. And '1.2.3.45' should not be replaced.