如何在 linux shell 中使用正则表达式从文件中提取 IP 地址?
Posted
技术标签:
【中文标题】如何在 linux shell 中使用正则表达式从文件中提取 IP 地址?【英文标题】:How do you extract IP addresses from files using a regex in a linux shell? 【发布时间】:2010-09-30 11:45:01 【问题描述】:如何在 linux shell 中通过正则表达式提取文本部分?可以说,我有一个文件,其中每一行都有一个 IP 地址,但位置不同。使用常见的 unix 命令行工具提取这些 IP 地址的最简单方法是什么?
【问题讨论】:
你可以试试我在这里发布的建议:unix.stackexchange.com/a/389565/249079 grep -E -o '((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]? )\.)3(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' file.txt 如果您需要确保不从65465656768128.0.0.1233453
之类的字符串中提取128.0.0.1
,请参阅this answer。
【参考方案1】:
如果您没有获得特定文件并且您需要提取 IP 地址,那么我们需要递归执行。 grep 命令 -> 搜索文本或文件以匹配给定的字符串并显示匹配的字符串。
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
我们可以搜索整个目录树,即当前目录和各级子目录。它表示递归搜索。
-o
只打印匹配的字符串
-E
使用扩展正则表达式
如果我们不使用管道之后的第二个 grep 命令,我们将获得 IP 地址及其所在路径
【讨论】:
不需要通过管道将 grep 导入 grep。【参考方案2】:您也可以使用 awk。有点像...
awk 'i=1; if (NF > 0) do if ($i ~ /regexp/) print $i; i++; while (i <= NF);' file
可能需要清洁。只是一个快速而肮脏的回应基本上显示了如何使用 awk 来完成。
【讨论】:
仍然是 grep 的那个看起来最优雅和简单 哦,同意。只是认为展示各种方法会很有用,以防有人想知道,特别是如何使用 awk 来完成。【参考方案3】: grep -E -o "([0-9]1,3[\.])3[0-9]1,3"
【讨论】:
这会打印出无效的 IP 地址。【参考方案4】:我只想从目录中的任何文件中获取以“10”开头的 IP 地址:
grep -o -nr "[10]\2\\.[0-9]\1,3\\.[0-9]\1,3\\.[0-9]\1,3\" /var/www
【讨论】:
【参考方案5】:对于那些想要从 apache 日志中获取 IP 地址并列出 IP 地址访问网站次数的现成解决方案的人,请使用以下行:
grep -Eo '[0-9]1,3\.[0-9]1,3\.[0-9]1,3\.[0-9]1,3' error.log | sort | uniq -c | sort -nr > occurences.txt
禁止黑客的好方法。接下来你可以:
-
删除访问次数少于 20 次的行
使用正则表达式剪切到单个空格,这样您就只有 IP 地址了
使用正则表达式剪切 IP 地址的最后 1-3 个数字,这样您就只有网络地址了
在每行的开头添加
deny from
和一个空格
将结果文件作为 .htaccess
【讨论】:
【参考方案6】:我写了一篇关于这个主题的博文:How to Extract IPv4 and IPv6 IP Addresses from Plain Text Using Regex。
本文详细介绍了最常见的 IP 不同模式,通常需要使用正则表达式从纯文本中提取和隔离。 本指南基于 CodVerter 的 IP Extractor 源代码工具,用于在必要时处理 IP 地址提取和检测。
如果您希望验证和捕获 IPv4 地址,此模式可以完成这项工作:
\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.])3(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
或使用前缀(“斜线表示法”)验证和捕获 IPv4 地址:
\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.])3(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?/[0-9]1,2)\b
或捕获子网掩码或通配符掩码:
(255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)
或者使用正则表达式negative lookahead过滤掉子网掩码地址:
\b((?!(255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)[.](255|254|252|248|240|224|192|128|0)))(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.])3(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
对于 IPv6 验证,您可以转到我在此答案顶部添加的文章链接。 下面是一个捕获所有常见模式的示例(取自 CodVerter 的 IP Extractor Help Sample):
如果您愿意,可以测试 IPv4 正则表达式 here。
【讨论】:
【参考方案7】:我已经尝试了所有答案,但他们都有一个或多个问题,我列出了其中的几个。
-
有些检测到
123.456.789.111
为有效IP
有些不会将127.0.00.1
检测为有效 IP
有些不检测以零开头的 IP,例如 08.8.8.8
所以我在这里发布了一个适用于上述所有条件的正则表达式。
注意:我已经提取了超过 200 万个 IP,使用以下正则表达式没有任何问题。
(?:(?:1\d\d|2[0-5][0-5]|2[0-4]\d|0?[1-9]\d|0?0?\d)\.)3(?:1\d\d|2[0-5][0-5]|2[0-4]\d|0?[1-9]\d|0?0?\d)
【讨论】:
【参考方案8】:这里的每个人都在使用真正的正则表达式,但真正理解 POSIX 的正则表达式将允许您使用像这样的一个小的 grep
命令来打印 IP 地址。
grep -Eo "(([0-9]1,3)\.)3([0-9]1,3)"
(旁注) 这不会忽略无效的 IP,但它非常简单。
【讨论】:
这也匹配...
似乎只有在我专门将...
输入命令时才会发生。在第一个括号之前添加[0-9]
似乎可以解决它。添加到命令中。如果您发现任何错误,请告诉我。
我想你想要"([0-9]+\.)3[0-9]+"
(否则你仍然可以匹配,例如0...
)。
我实际上遇到了那个问题。当我在使用 for 循环和tr -dc '0-9.' </dev/urandom | head -c 16
创建的文件上使用它时,它会打印出各种错误的行。但是我认为(([0-9]1,3)\.)3([0-9]1,3)
正在接近紧凑,因为它不会打印不正确的行,例如0...111230..24...
。但是,它还没有检查每个八进制数是否为0
或大于255
。我现在正在做的事情。【参考方案9】:
之前的所有答案都有一个或多个问题。接受的答案允许像 999.999.999.999 这样的 IP 号码。当前第二个最多支持的答案需要以 0 为前缀,例如 127.000.000.001 或 008.008.008.008 而不是 127.0.0.1 或 8.8.8.8。 Apama 几乎是正确的,但是该表达式要求 ipnumber 是该行中唯一的内容,不允许前导或尾随空格,也不能从行中间选择 ip。
我认为正确的正则表达式可以在http://www.regextester.com/22上找到
因此,如果您想从文件中提取所有 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
如果此正则表达式仍有问题,请发表评论。这个问题很容易找到很多错误的正则表达式,我希望这个没有真正的问题。
【讨论】:
我发现这个表达式从输入ip“256.1.1.1”中选择“56.1.1.1”。我认为这是正确的。 256.1.1.1不是合法的ip号,所以正确的ip一定是56.1.1.1。【参考方案10】: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地址的位置在开头、结尾和中间的某个地方
第一个正则表达式在行首查找 ip 地址的完全匹配。 or 之后的第二个正则表达式在中间查找 ip 地址。我们匹配它的方式是,后面的数字应该正好是 1 到 3 位数字。可以排除像 12345.12.34.1 这样的虚假 ips。
第三个正则表达式在行尾查找ip地址
【讨论】:
cat
在这里没用。 grep
将接受文件作为输入以及带有重定向的命令输出。【参考方案11】:
这在访问日志中对我来说很好。
cat access_log | egrep -o '([0-9]1,3\.)3[0-9]1,3'
让我们逐个分解。
[0-9]1,3
表示 [] 中提到的范围出现 1 到 3 次。在这种情况下,它是 0-9。所以它匹配像 10 或 183 这样的模式。
后跟一个“.”。我们需要将其转义为“。”是一个元字符,对 shell 有特殊意义。
所以现在我们处于“123”这样的模式。 “12。”等等
这种模式会重复三次(带有“.”)。所以我们用括号括起来。
([0-9]1,3\.)3
最后,模式会重复,但这次没有“.”。这就是为什么我们在第三步中单独保存它。 [0-9]1,3
如果 ips 在我的情况下每行的开头,请使用:
egrep -o '^([0-9]1,3\.)3[0-9]1,3'
其中 '^' 是一个锚点,告诉我们在行首进行搜索。
【讨论】:
打印无效的IP地址。【参考方案12】:您可以使用我制作的一些 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
【讨论】:
【参考方案13】:对于centos6.3
ifconfig eth0 | grep 'inet addr' | awk 'print $2' | awk 'BEGIN FS=":" print $2'
【讨论】:
【参考方案14】:我写了一点script 来更好地查看我的日志文件,这没什么特别的,但可能会帮助很多正在学习 perl 的人。它在提取 IP 地址后对 IP 地址进行 DNS 查找。
【讨论】:
【参考方案15】:此处的大多数示例将匹配 999.999.999.999,这在技术上不是有效的 IP 地址。
以下将仅匹配有效的 IP 地址(包括网络和广播地址)。
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。
【讨论】:
这也匹配 1233.123.123.123 技术上它匹配 233.123.123.123,即使它前面有一个 1。它不限制 IP 地址前后的内容。 有没有办法把路径、文件名、行号连同匹配的IP一起吐出来? 如果添加 -n 参数,它也会打印行号。如果您指定多个文件,如 *.txt,那么它也会打印文件名。如果你使用 -r 它将搜索子目录并打印文件的完整路径。 这个和127.0.0.1不匹配,规则要求写成127.000.000.001,这不是标准的写法吗?另一个例子是 8.8.8.8 需要写成 008.008.008.008。为什么要投票 36 次?我错过了什么吗?【参考方案16】:我通常从 grep 开始,以获得正确的正则表达式。
# [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
那时我通常会对sed
感到恼火,因为我没有使用与其他人相同的正则表达式。所以我搬到perl
。
$ perl -nle '/[0-9]1,3\.[0-9]1,3\.[0-9]1,3\.[0-9]1,3/ and print $&'
无论如何,了解 Perl 是一件好事。如果您安装了一点点 CPAN,您甚至可以以较低的成本使其更可靠:
$ perl -MRegexp::Common=net -nE '/$REnetIPV4/ and say $&' file(s)
【讨论】:
【参考方案17】:您可以使用sed。但是,如果您了解 perl,从长远来看,这可能会更容易,也更有用:
perl -n '/(\d+\.\d+\.\d+\.\d+)/ && print "$1\n"' < file
【讨论】:
【参考方案18】:您可以使用grep 将它们拉出来。
grep -o '[0-9]\1,3\\.[0-9]\1,3\\.[0-9]\1,3\\.[0-9]\1,3\' file.txt
【讨论】:
我必须删除斜线,它起作用了:egrep -o '[0-9]1,3\.[0-9]1,3\.[0-9]1,3\.[0-9]1,3' file
grep -o '[0-9]\1,3\\.[0-9]\1,3\\.[0-9]\1,3 \\.[0-9]\1,3\' 文件.txt |排序 | uniq 表示唯一的 IP 地址。
让它更干净一点:grep -o '([0-9]1,3\.)3[0-9]1,3'
我在这里迟到了,但我希望能清楚地得到答案。为什么需要在大括号内包含反斜杠?我尝试使用删除这些反斜杠的人给出的答案,但它不起作用。我知道反斜杠允许您 grep 将句点作为文字阅读,但我不明白为什么您会将大括号作为文字阅读。任何澄清都会有所帮助。【参考方案19】:
我建议使用 perl。 (\d+.\d+.\d+.\d+) 应该可以解决问题。
编辑:为了让它更像一个完整的程序,您可以执行以下操作(未经测试):
#!/usr/bin/perl -w
use strict;
while (<>)
if (/(\d+\.\d+\.\d+\.\d+)/)
print "$1\n";
每行处理一个 IP。如果每行有多个 IP,则需要使用 /g 选项。 man perlretut 为您提供更详细的正则表达式教程。
【讨论】:
您总是可以将其写在一行中并使用 perl -n 或 perl -e 来执行它,但恕我直言,这样的小脚本更容易处理,特别是如果您想保留并修改它稍后再了解其他模式。以上是关于如何在 linux shell 中使用正则表达式从文件中提取 IP 地址?的主要内容,如果未能解决你的问题,请参考以下文章
关于linux的shell的正则表达式,如何在输入的变量一组字符中提取第一个非数字字符!求解答