我有一个巨大的文本文件,其中包含各种乱码的 IP 地址,但不在一个单元中
例如。
那么@192@你到底在我家@168@干什么呢?[电子邮件保护]@16@ 不应该在这里。
我想要的是创建一个输出文件,并在其中创建如下所示的 ipadresses 文件
1.192.168.10.16
2.192.223.22.44
etc..
我对正则表达式有很好的理解,可以从文本文件中提取特定信息,但在这里我需要将这些结合起来,这让我感到困惑。应该如何解决这样的问题?我正在使用 Ubuntu 12.04。
答案1
我能想到的最简单的方法是,假设您想要的数字始终由@
符号分隔:
$ grep -oP '@\K\d+' file | perl -pe '$. % 4 != 0 && s/\n/./;'
192.168.10.16
192.169.10.16
192.128.10.16
192.162.10.16
不过,这不会对行进行编号,因此要添加它们,请执行以下操作
$ grep -oP '@\K\d+' file | perl -pe '$. % 4 != 0 && s/\n/./;' | perl -pe 's/^/$.. /'
1. 192.168.10.16
2. 192.169.10.16
3. 192.128.10.16
4. 192.162.10.16
解释
grep -oP '@\K\d+' file
:-o
表示“仅打印行的匹配部分”,并-P
为 启用 Perl 兼容正则表达式 (PCRE)grep
。这让我们可以使用 来\d
匹配数字,最重要的是, ,\K
这意味着“忘记在我之前匹配的任何内容”。\K
让我 grep@\K10
并只打印10
因为@
在 之前\K
。perl -pe
:逐行读取输入文件,将给出的脚本应用-e
到每一行,然后打印该行(-p
)。'$. % 4 != 0 && s/\n/./;
:%
是个取模运算符,是输入文件的当前行号。此代码将在以下行上$.
用换行符 (\n
)替换.
不是能被 4 整除。结果是,由于我们给它输入了一个数字列表( 的输出grep
),每组 4 个数字将打印在同一行上,因为\n
已转换为.
。perl -pe 's/^/$.. /'
:只需将当前行号添加到每行的开头。
钢铁司机建议一个非常好的选择:
grep -oP '@\K\d+' file | xargs -n4 printf '%d.%d.%d.%d\n' | cat -n
这让我想到了这个:
printf '%d.%d.%d.%d\n' $(grep -oP '@\K\d+' file ) | cat -n
如果您愿意,您可以用 Perl 完成整个操作并避免使用管道,但我会使用上面的方法。无论如何,始终假设您的数字被 包围@
,这也会起作用:
perl -ne 'push @f,(/@(\d+)@/g);
END{
$k=1;
for($i=0;$i<=$#f;$i+=4){
print "$k. " . join(".",@f[$i..($i+3)]) . "\n"; $k++}
}' file
您可以将其直接粘贴到终端中,只需更改file
为实际文件名即可。输出如下所示:
1. 192.168.10.16
2. 192.169.10.16
3. 192.128.10.16
4. 192.162.10.16
解释
perl -ne
:逐行读取输入文件(-n
)并应用给出的脚本-e
。push @f,(/@(\d+)@/g);
:将 包围的每个数字保存@
为数组的一个元素@f
。END{}
:处理完所有行后执行此操作for($i=0;$i<=$#f;$i+=4){}
:遍历数组。由于 IP 有 4 组数字,因此我们以 4 为一跳的方式读取数组。join(".",@f[$i..($i+3)])
:这将数组的 4 个元素连接起来.
以便打印。- 这
$k
只是打印 IP 前面的数字。
答案2
使用 GNUsed
您也可以将其用于sed
此目的。假设 ipaddress 中的数字存在于@@
符号之间。
$ sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/\1.\2.\3.\4/g' file
192.168.10.16
192.169.10.16
192.128.10.16
192.162.10.16
下面的命令将数字按顺序排列在获取的 IP 地址之前,
$ sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/\1.\2.\3.\4/g' file | awk '{ print NR". "$0}'
例子:
$ echo 'So what the@192@ heck are you doing@168@ in my house @[email protected] were not @16@ supposed to be here.' | sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/\1.\2.\3.\4/g' | awk '{ print NR". "$0}'
1. 192.168.10.16
请稍微解释一下你的代码?
sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/\1.\2.\3.\4/g' file | awk '{ print NR". "$0}'
| | | |
| | | |
|<----------------------First part--------------------------------->| |<-----Second part--->|
OP 提到,IP 地址在整个文件中都是杂乱无章的(分散的),每个部分都包含在其中@@
,每行包含四个@...@
部分。因此,他想@@
逐行提取其中存在的所有数字,并以 ip 地址格式 ( xxx.xxx.xxx.xxx
) 打印出来。
第一部分
sed
逐行解析输入文件。
考虑一下我代码中的以下正则表达式以及上面提到的例子。我们必须给出与整行匹配的正则表达式,并且它还包含获取组,以便根据我们的标准获取单词,这样获取的组就可以通过反向引用重新使用。
示例行:
So what the@192@ heck are you doing@168@ in my house @[email protected] were not @16@ supposed to be here.
正则表达式:
.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*
.*
它匹配除换行符之外的任意字符 0 次或更多次。
@\(.*\)@
在sed
, ()
(抓取组)中,这些括号用于抓取字符、单词或数字组。默认情况下,sed 使用基本正则表达式,因此我们必须转义括号才能使抓取功能正常工作。但是,如果您使用带有-r
( extended-regex
) 标志的 sed,则无需转义。
在我们的例子中是\(.*\)
,左括号和右括号均被转义。sed 读取整行后,会停止匹配并开始获取符号后的所有字符或数字或任何内容@
,直到找到下一个@
符号后才停止获取。然后,它将获取的组存储在称为(模式空间)的特殊缓冲区中。以便进一步使用获取的字符。现在 sed 获取第一个符号之间的数字@@
(即 .192)。
.*
捕获第一组后,sed
开始解析下一个字符并匹配任何内容 0 次或更多次。
@\(.*\)@
取出第二个符号之间的数字@@
。(例如 168)
.*
匹配任意一个然后继续。
@\(.*\)@
取出第三部分之间的数字@@
。(即10)
.*
匹配任意一个然后继续。
@\(.*\)@
取出第四部分之间的数字@@
。(即16)
.*
第四个符号后面可能有或没有字符@@
。因此我们必须给出这个.*
才能匹配第四 @@
部分之后的所有字符。
因此sed
获取我们想要的精确数字并将其存储在缓冲区中。
默认格式(语法)为sed
,
sed 's/regex/replacement/g' file
代码:
sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/\1.\2.\3.\4/g' file
因此 sed 搜索此正则表达式的匹配项。一旦找到匹配项,它将被替换部分替换。g
全局标志有助于用替换部分替换所有出现的正则表达式字符串。( g-global
)。
在我们的例子中,正则表达式将匹配第一行,整行将被我们获取的组1
, 2
, 3
,替换4
。然后 sed 对所有与我们的正则表达式匹配的行执行此操作。在替换部分,获取的组以 开头\
。因此它被称为反向引用。如果我们未能用.
(点)分隔组,
\1\2\3\4
输出结果为,
1921681016
所以我们必须用.
(点)分隔各组。这样它才会以 IP 地址格式出现。
\1.\2.\3.\4
现在输出将是,
192.168.10.16
第二部分
awk '{ print NR". "$0}'
现在第一行的 sed 输出将是192.168.10.16
。此输出将作为第二条命令的输入awk
。
Awk 的
NR
(记录数)变量存储行或记录号。请注意,的最后一个值NR
将是最后一个行号。与 一样sed
,awk
逐行解析输入文件。因此NR
第一行的值将是 1,第二行将是,2
依此类推。在 awk 的打印函数中,如果将字符放在双引号内,则会按原样打印该字符。因此它会
.
在行号(即当前 NR)之后打印。$0
按原样打印整行。
因此整个命令的输出将是,
$ sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/\1.\2.\3.\4/g' file | awk '{ print NR". "$0}'
192.168.10.16
192.169.10.16
192.128.10.16
192.162.10.16
您也可以使用此命令,
sed 's/.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*/\1.\2.\3.\4/g' file
例子:
$ echo 'So what the@192@ heck are you doing@168@ in my house @[email protected] were not @16@ supposed to be here.' | sed 's/.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*/\1.\2.\3.\4/g'
192.168.10.16
答案3
可能有一种使用终端执行此操作的奇特方法,但我不知道该怎么做。以下是我使用 Python 执行此操作的方法
将此代码复制到新文件中,将其命名为 whatEverYouWant.py,并将“input.txt”行更改为“yourFileWithIps.txt”
import re
validIpAddressRegex = "^(([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])$";
ips = []
with open('input.txt','r') as f:
output = f.read()
ips = re.findall(r'[0-9]+(?:\.[0-9]+){3}', output)
for x in range(1, len(ips) + 1):
print str(x) + '.' + ips[x-1]
然后从终端导航到你保存 whatEverYouWant.py 的位置并输入
python whatEverYouWant.py
这样就应该输出您想要的内容。
我自己测试的结果
cam@cam-P5E:~/Desktop$ python getips.py
1.192.168.0.1
2.255.255.255.0
3.10.0.0.1
4.192.192.192.192