我正在寻找一个正则表达式,用于grep
从包含 IPv4 和 IPv6 地址的任意文件中过滤掉它们。我希望 IPv4 地址的行为如下:
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]?)"
我知道这里有几个类似的问题和答案,但大多数只关注 IPv4 地址和我找到的最好的答案对我不起作用。使用 时,该表达式不会为我输出任何 IP 地址grep
。
由于这个问题显然不明确,我正在寻找组合的正则表达式。它将输出任何有效的 IP 地址。作为奖励,甚至可以在一条线上有多个。
如果由于某种原因这不容易做到grep
,我愿意接受替代方案,只要它们简单,在 BSD 系统上工作并且不需要 GNU 工具。
答案1
替代的非grep
基于perl
方法使用正则表达式::常见包(作为 FreeBSD 端口以名称 提供p5-Regexp-Common
):
perl -MRegexp::Common=net -nE 'say $& while /$RE{net}{IPv4}|$RE{net}{IPv6}/g' input.txt
例子:
$ cat input.txt
some words
a line with 127.0.0.1 and 192.168.1.1 in it.
more words
some line with ::1 in it.
$ perl -MRegexp::Common=net -nE 'say $& while /$RE{net}{IPv4}|$RE{net}{IPv6}/g' input.txt
127.0.0.1
192.168.1.1
::1
答案2
由于你的操作系统 (FreeBSD) 默认带有编译器和词法分析器(就像任何 Unix 系统应该的那样),最好使用它们来编写一个小程序,而不是一些没人能理解的糟糕的正则表达式。
$ cat > ipv46.l <<'EOT'
%{
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
%}
W [0-9A-Za-z_]+
I4 ([0-9]+[.]){3}[0-9]+
I6 ([0-9a-fA-F]|::)[0-9a-fA-F:]*{I4}?
%%
{I6}|{I4} {
struct in6_addr a6; struct in_addr a; char b[INET6_ADDRSTRLEN];
if(inet_pton(AF_INET6, yytext, &a6))
printf("%s\n", inet_ntop(AF_INET6, &a6, b, sizeof b));
else if(inet_pton(AF_INET, yytext, &a))
printf("%s\n", inet_ntop(AF_INET, &a, b, sizeof b));
}
{W}|.|\n ;
EOT
$ lex ipv46.l && cc lex.yy.c -o ipv46 -ll
$ ./ipv46 <file
$ ./ipv46
::0:0:1 1:::1 ::
::1
::
::FFFF:127.0.0.1:80
::ffff:127.0.0.1
...
这是相当严格的;它不会127.0.0.1
从foo127.0.0.1.12
或中提取地址foo:127.0.0.1bar
。但它将能够从 tcpdump 的address.port
形式或通常的形式中提取它ipv4:port
,并且它将能够处理“混合”ipv4/ipv6 地址。
答案3
这应该提取 IPv4 和 IPv6 地址:
grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}'
但是,它不会检查 IPv6 地址是否真正有效,因为它们可能包含超过 1 个::
。
答案4
这应该对 IPv4 进行错误检查并且更加紧凑
grep -Eo '([0-255]\.){3}[0-255]|([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}'