使用子网掩码对IP地址列表进行排序,删除重复项



我有一个包含这些IP地址的txt文件,希望对它们进行排序,删除重复的IP地址,但保留/subnet。

4.4.4.4/32
4.2.2.2/32
4.4.4.4/32
4.2.2.2/32
4.2.2.2/28
4.4.4.4/24
2.2.2.2/32

例如:在排序并删除重复项后,以上内容将变为

4.4.4.4/32
4.2.2.2/32
4.2.2.2/28
4.4.4.4/24
2.2.2.2/32

使用awk、perl或python有什么技巧吗?我还想按升序排序。

您应该能够使用sort -ur来完成此操作。

编辑:要在python中做到这一点,您可以执行以下操作:

with open('ipaddress.txt', 'r') as f:
address = sorted(list(set(line for line in f)), reverse=True)
for ad in address:
print(ad)

由于数据看起来非常规则,因此使用参数可以很容易地确保Python中的正确排序。这用于为列表中要排序的每个实例创建一个"排序键"。人们经常使用lambda作为排序键函数,但为了完整性,我们将define一些有用的函数。

重复删除最好在Python中排序之前完成。由于列表无论如何都必须进行排序,因此将其转换为集合将导致唯一字符串的任意排序并不重要,如果在Python中排序无关紧要,则"uniquiify"列表l的简单方法是

l = list(set(l))

顺便说一句,你的测试数据选择得很糟糕,因为它会在词法排序中正确排序(只是偶然)。所以你最好在地址中包含一些带有两位数和三位数成分的例子,这样就不再是这样了。我通过解释的方式展示了非工作类型。

In [42]: data = """
4.4.4.4/32
4.2.2.2/32
4.4.4.4/32
4.2.2.2/32
4.2.2.2/28
4.4.4.4/24
2.2.2.2/32
12.13.14.15/24
11.12.13.14/24""".splitlines()
In [43]: data.sort()
In [44]: data
Out[44]: 
['11.12.13.14/24',
'12.13.14.15/24',
'2.2.2.2/32',
'4.2.2.2/28',
'4.2.2.2/32',
'4.2.2.2/32',
'4.4.4.4/24',
'4.4.4.4/32',
'4.4.4.4/32']
In [45]: data = list(set(data))
In [46]: data.sort()
In [47]: data
Out[47]: 
['11.12.13.14/24',
'12.13.14.15/24',
'2.2.2.2/32',
'4.2.2.2/28',
'4.2.2.2/32',
'4.4.4.4/24',
'4.4.4.4/32']
In [48]: def sortkey(addr):
....:     add, pref = addr.split("/")
....:     a, b, c, d = (int(x) for x in add.split("."))
....:     return a, b, c, d, int(pref)
....: 
In [49]: data.sort(key=sortkey)
In [50]: data
Out[50]: 
['2.2.2.2/32',
'4.2.2.2/28',
'4.2.2.2/32',
'4.4.4.4/24',
'4.4.4.4/32',
'11.12.13.14/24',
'12.13.14.15/24']

排序键函数在Python中并不重要,因为作为"装饰/排序/取消装饰"算法的一部分,它只应用于每个列表值一次。更普遍地说,对于这个问题域,你可能会发现ipad地址模块很有用:http://docs.python.org/dev/howto/ipaddress.html

在python中你可以做:

In [3]: l = []
In [4]: with open('ipaddress.txt', 'r') as input_file:
...:     for elem in input_file.readlines():
...:         if elem.strip() not in l:
...:             l.append(elem.strip())
...:
In [5]: l
Out[5]: ['4.4.4.4/32', '4.2.2.2/32', '4.2.2.2/28', '4.4.4.4/24', '2.2.2.2/32']

您可以使用awk:按照文件中出现的顺序获得唯一的行

awk '!seen[$0]++'

如果你想要整个管道:

awk '/#/{sub(/#.*/,"",$0)} length($0) && !seen[$0]++' ipnum.txt

未经测试

最新更新