如何在 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.' &lt;/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的正则表达式,如何在输入的变量一组字符中提取第一个非数字字符!求解答

Linux Shell正则表达式如何匹配1~3位数字

Linux Shell编程 - 正则表达式

在linux的shell语言中,怎样用正则表达式来截取字符串?

Linux Shell编程

linux基础:shell中的正则表达式用法大全