Contents

如何在Linux中从文件中提取IPv4地址

1. 概述

我们有时需要从包含一长串 IP 地址的文件中提取IP 地址。例如,这可能来自服务器的访问日志文件。

在本教程中,我们将探索可用于从文件中提取 IPv4 地址的不同方法。

2. 设置

让我们创建一个文件sample.log,其中包含几行访问日志文件:

$ touch sample.log

然后我们用 Nano 编辑器打开它:

$ nano sample.log

接下来,让我们粘贴这些日志条目并保存文件:

13.66.139.0 - - [19/Dec/2020:13:57:26 +0100] "GET /index.php?option=com_phocagallery&view=category&id=1:almhuette-raith&Itemid=53 HTTP/1.1" 200 32653 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" "-"
157.48.153.185 - - [19/Dec/2020:14:08:06 +0100] "GET /apache-log/access.log HTTP/1.1" 200 233 "-" "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" "-"
157.48.153.185 - - [19/Dec/2020:14:08:08 +0100] "GET /favicon.ico HTTP/1.1" 404 217 "http://www.almhuette-raith.at/apache-log/access.log" "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" "-"
216.244.66.230 - - [19/Dec/2020:14:14:26 +0100] "GET /robots.txt HTTP/1.1" 200 304 "-" "Mozilla/5.0 (compatible; DotBot/1.1; http://www.opensiteexplorer.org/dotbot, [[email protected]](/cdn_cgi/l/email_protection))" "-"
54.36.148.92 - - [19/Dec/2020:14:16:44 +0100] "GET /index.php?option=com_phocagallery&view=category&id=2%3Awinterfotos&Itemid=53 HTTP/1.1" 200 30662 "-" "Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/)" "-"
92.101.35.224 - - [19/Dec/2020:14:29:21 +0100] "GET /administrator/index.php HTTP/1.1" 200 4263 "" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-"
73.166.162.225 - - [19/Dec/2020:14:58:59 +0100] "GET /apache-log/access.log HTTP/1.1" 200 1299 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.101 Safari/537.36" "-"

上面的每一行代表这种格式的不同条目:

IP-ADDRESS - - [TIMESTAMP] REQUEST & REQUEST-INFORMATION

在接下来的部分中,我们将探讨从该文件中提取 IP 地址的不同方法。

3. 使用grep

**Linux grep 命令是用于在一个或多个文件中搜索特定字符串的最强大的实用程序之一。**在我们必须搜索大型访问日志文件的情况下,它非常有用。

我们将通过创建一个匹配 IP 地址格式的正则表达式模式来使用它:

$ grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' sample.log
13.66.139.0
157.48.153.185
157.48.153.185
216.244.66.230
54.36.148.92
92.101.35.224
73.166.162.225

我们有一个包含四个相同部分的正则表达式,在上面的命令中每个部分用一个点分隔。每个正则表达式代表 0 到 9 范围内的一到三位数字。

默认情况下,grep命令打印包含匹配模式的整行。我们使用-o*选项修剪结果并仅打印匹配的部分。*

上面的正则表达式有缺陷,因为它也可以匹配超出有效 IPv4 地址范围的 IP 地址。我们只能在确定输入文件仅包含有效 IPv4 地址的情况下使用它。

3.1. 仅提取有效的 IPv4 地址

为了使事情更严格,让我们修改正则表达式以仅匹配有效的 IPv4 地址。

为了有效地测试这一点,让我们在sample.log文件的末尾添加一个 IP 地址,例如*“999.888.777.666” *:

$ echo "999.888.777.666" >> sample.log

这将在文件末尾添加无效的 IP 地址。

然后我们可以修改正则表达式并再次运行grep

$ grep -Eo '(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]?)' sample.log
13.66.139.0
157.48.153.185
157.48.153.185
216.244.66.230
54.36.148.92
92.101.35.224
73.166.162.225

这个正则表达式更加严格,因为它只匹配四个部分中每个部分的值等于或小于 255 的 IP 地址。

我们使用*-E选项将模式解释为扩展正则表达式 (ERE),并使用-o*选项修剪结果并仅打印匹配的部分。

我们可以进一步推动事情并将结果传递给/uniqsort 命令。这会按升序对记录进行计数和排序。它还过滤列表,因此它只会打印唯一的 IP 地址及其各自的计数:

$ grep -Eo '(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]?)' sample.log | uniq -c | sort
      1 13.66.139.0
      1 216.244.66.230
      1 54.36.148.92
      1 92.101.35.224
      1 73.166.162.225
      2 157.48.153.185

我们将*-c选项传递给uniq*命令以获取单个 IP 地址的总数。

4. 使用 Perl

**Perl代表实用提取和报告语言。它在打印基于通过文件或标准输入的数据输入的报告时很有用。**它已经发展成为一种通用语言,用于编写从快速单行程序到全面应用程序的程序。

我们可以使用 Perl 使用与之前相同的正则表达式来提取有效的 IP 地址:

$ perl -nle '/(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]?)/ and print $&' sample.log
13.66.139
157.48.153
157.48.153
216.244.66
54.36.148
92.101.35
73.166.162

我们使用-n选项向-e选项执行的代码添加循环。-l*选项确保每条记录都打印在其行上,从而提高了可读性。*

我们还可以通过 Perl 命令使用管道来获取每个 IP 地址的总计数,然后将结果按升序或降序排序:

$ perl -nle '/(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]?)/ and print $&' sample.log | uniq -c | sort
      1 13.66.139.0
      1 216.244.66.230
      ...truncated...

我们甚至可以通过使用输出重定向 ( » ) 选项并指定输出文件将结果保存到输出文件:

$ perl -nle '/(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]?)/ and print $&' sample.log >> output_file.txt

5. 使用awk

**awk 命令是一个 Linux 实用程序,用于处理数据并根据数据生成报告。**它让我们可以编写小而有效的程序作为定义要搜索的文本模式的语句。此外,我们可以定义在找到匹配项时执行的操作。

让我们看看如何使用awk命令从sample.log文件中提取所有 IP 地址:

$ awk 'match($0, /(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]?)/) {print substr($0, RSTART, RLENGTH)}' sample.log
13.66.139
157.48.153
157.48.153
216.244.66
54.36.148
92.101.35
73.166.162

我们使用 match()函数来定义一个字符串和一个正则表达式。然后我们打印一个包含字符串 ( $0 ) 和预定义变量RSTARTRLENGTH的子字符串。这些变量表示匹配字符串的字符的索引和长度。

或者,如果我们从与sample.log文件格式相同的有效访问日志文件中获取 IP 地址列表,我们可以简单地使用awk获取第一列:

$ awk '{print $1}' sample.log 
13.66.139.0
157.48.153.185
157.48.153.185
216.244.66.230
54.36.148.92
92.101.35.224
73.166.162.225

第一列通常是大多数访问日志文件中的 IP 地址。