你如何从Linux文件中使用正则expression式提取IP地址?

如何在Linux shell中通过regexp提取文本部分? 可以这么说,我在每一行都有一个IP地址,但是在不同的位置。 使用常用的unix命令行工具提取这些IP地址的最简单方法是什么?

你可以用grep把它们拉出来。

grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' file.txt 

这里的大多数例子都会在999.999.999.999上匹配,这在技术上并不是有效的IP地址。

以下内容仅适用于有效的IP地址(包括networking地址和广播地址)。

 grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' file.txt 

如果要查看匹配的整个行,请忽略-o。

我通常从grep开始,正确地得到正则expression式。

 # [multiple failed attempts here] grep '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' file # good? grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' file # good enough 

然后,我会尝试将其转换为sed来过滤掉其余的行。 (在阅读完这篇文章后,你和我不会再这么做了:我们将使用grep -o来代替)

 sed -ne 's/.*\([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\).*/\1/p # FAIL 

那时候我通常会因为不使用和其他人相同的正则expression式而恼火于sed 。 所以我搬到perl

 $ perl -nle '/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ and print $&' 

无论如何,Perl都是很好的例子。 如果你已经安装了less量的CPAN,你甚至可以用很less的成本使它更可靠:

 $ perl -MRegexp::Common=net -nE '/$RE{net}{IPV4}/ and say $&' file(s) 

这在我的访问日志中工作正常。

 cat access_log | egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}' 

让我们一个一个地打破它。

  • [0-9]{1,3}表示在[]中提到的一到三个范围。 在这种情况下,它是0-9。 所以它匹配10或183的模式。

  • 后面跟着一个'。'。 我们将需要逃避这个'。' 是一个元字符,对壳有特殊的意义。

所以现在我们处于“123”模式。 '12“。 等等

  • 这种模式重复三次(用'。')。 所以我们把它括在括号里。 ([0-9]{1,3}\.){3}

  • 最后这个模式重演,但是这次没有'。'。 这就是为什么我们在第三步分开保存它的原因。 [0-9]{1,3}

如果ips位于每行的开头,就像我的情况一样:

 egrep -o '^([0-9]{1,3}\.){3}[0-9]{1,3}' 

其中“^”是指示在行首开始search的锚点。

我写了一个脚本来更好地查看我的日志文件,没有什么特别的,但是可能会帮助很多正在学习perl的人。 在提取IP地址后,它会对IP地址进行DNS查找。

grep -E -o“([0-9] {1,3} [。]){3} [0-9] {1,3}”

你可以使用一些我所做的shell帮助程序: https : //github.com/philpraxis/ipextract

包括他们在这里为了方便:

 #!/bin/sh ipextract () { egrep --only-matching -E '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' } ipextractnet () { egrep --only-matching -E '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[[:digit:]]+' } ipextracttcp () { egrep --only-matching -E '[[:digit:]]+/tcp' } ipextractudp () { egrep --only-matching -E '[[:digit:]]+/udp' } ipextractsctp () { egrep --only-matching -E '[[:digit:]]+/sctp' } ipextractfqdn () { egrep --only-matching -E '[a-zA-Z0-9]+[a-zA-Z0-9\-\.]*\.[a-zA-Z]{2,}' } 

从shell中加载它(当存储在ipextract文件中时):

$。 ipextract

使用它们:

 $ ipextract < /etc/hosts 127.0.0.1 255.255.255.255 $ 

对于一些实际使用的例子:

 ipextractfqdn < /var/log/snort/alert | sort -u dmesg | ipextractudp 

你可以使用sed 。 但是如果你知道perl,从长远来看,这可能会更容易,更有用:

 perl -n '/(\d+\.\d+\.\d+\.\d+)/ && print "$1\n"' < file 

我build议perl。 (\ d +。\ d +。\ d +。\ d +)应该可以做到这一点。

编辑:只是为了使它更像一个完整的程序,你可以做下面的事情(未经testing):

 #!/usr/bin/perl -w use strict; while (<>) { if (/(\d+\.\d+\.\d+\.\d+)/) { print "$1\n"; } } 

这每行处理一个IP。 如果每行有多个IP,则需要使用/ g选项。 man perlretut给你一个正则expression式的更详细的教程。

你也可以使用awk。 就像是 …

awk'{i = 1; if(NF> 0)do {if($ i〜/ regexp /)print $ i; i ++;} while(i <= NF);}'文件

– 可能需要清洁。 只是一个快速和肮脏的反应,基本上显示如何用awk做到这一点

如果你没有给出一个特定的文件,你需要提取IP地址,那么我们需要recursion地做。 grep命令 – >search文本或文件以匹配给定的string并显示匹配的string。

grep -roE'[0-9] {1,3}。[0-9] {1,3}。[0-9] {1,3}。[0-9] {1,3}'| grep -oE'[0-9] {1,3}。[0-9] {1,3}。[0-9] {1,3}。[0-9] {1,3}'

-r – >我们可以search整个目录树,即当前目录和所有级别的子目录。 它表示recursionsearch。

-o – >仅打印匹配的string

-E – >使用扩展的正则expression式

如果我们不会在pipe道之后使用第二个grep命令,那么我们将获得IP地址以及它所在的path

 cat ip_address.txt | grep '^[0-9]\{1,3\}[.][0-9]\{1,3\}[.][0-9]\{1,3\}[.][0-9]\{1,3\}[,].*$\|^.*[,][0-9]\{1,3\}[.][0-9]\{1,3\}[.][0-9]\{1,3\}[.][0-9]\{1,3\}[,].*$\|^.*[,][0-9]\{1,3\}[.][0-9]\{1,3\}[.][0-9]\{1,3\}[.][0-9]\{1,3\}$' 

让我们假设该文件是逗号分隔的,并在开始,结束和中间的某个地方的IP地址的位置

第一个正则expression式查找行首的IP地址的完全匹配。 第二个正则expression式在中间或后面查找ip地址,我们匹配的方式是后面的数字应该是1到3位数字,像12345.12.34.1这样的falsy ips可以排除在外。

第三个正则expression式在行尾查找ip地址

所有以前的答案都有一个或多个问题。 接受的答案允许IP号码,如999.999.999.999。 当前第二个最高的答案要求前缀为0,例如127.000.000.001或008.008.008.008,而不是127.0.0.1或8.8.8.8。 Apama几乎是正确的,但是expression式要求ipnumber是唯一的行,不允许前导或尾随空间,也不能从一行中selectip。

我认为正确的正则expression式可以在http://www.regextester.com/22find

所以,如果你想从一个文件中提取所有的IP地址使用:

 grep -Eo "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])" file.txt 

如果你不想重复使用:

 grep -Eo "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])" file.txt | sort | uniq 

请评论如果在这个正则expression式仍然有问题。 这个问题很容易find很多错误的正则expression式,我希望这个没有真正的问题。

对于centos6.3

ifconfig eth0 | grep 'inet addr' | awk '{print $2}' | awk 'BEGIN {FS=":"} {print $2}'