3

I'm trying to sort IP Addresses which I'm reading into a python script and printing out. The code that I've drafted up reads and prints the contents of a file (see example)

#!/usr/bin/python

f = open('file.txt', 'r')
file_contents = f.read()
print (file_contents)
f.close()

My issue is how do I take that importing of IP Addresses and sort them correctly? At the command line I would normally pass the file through a simple sort command (sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 ). But how can I get python to sort the IPs it's reading from the file so the output is sorted correctly, taking into consideration the 0-255 numbering schema for each octet of an IP?

Thanks,

ZdaR
  • 22,343
  • 7
  • 66
  • 87
Alby
  • 426
  • 2
  • 7
  • 17
  • So you want the IP's to be sorted in this way - `0.0.0.0, 0.0.0.1, --------.255.255` ? . – Gurupad Mamadapur Feb 07 '17 at 11:16
  • That is correct. I want all the IPs to end up being sorted in that fashion. Obviously they will all be different addresses (think random IP addresses), but I want them all in a sorted format such as: 10.11.12.13 -> 128.2.4.6 -> 192.0.3.4 -> 208.11.45.8... and so on. – Alby Feb 07 '17 at 11:22
  • Then this answer will solve your problem - http://stackoverflow.com/a/6545088/3225001 – Gurupad Mamadapur Feb 07 '17 at 11:29

2 Answers2

6

You can use the built-in ipaddress module:

#!/usr/bin/python
import ipaddress

with open('file.txt', 'r') as f:
   ips = sorted(ipaddress.ip_address(line.strip()) for line in f)
   print('\n'.join(map(str, ips)))

If you're using an older Python version (before 3.3), you may need my backport. Also note that this code employs the with statement for file I/O, as this handles errors correctly.

With ipaddress, the IP addresses are actually tested for validity. Also, the code can correctly handle IPv6 addresses (i.e. ::1.2.3.4 > 000::12a0) as well as esoteric representations such as 2130706433, although you cannot mix IPv4 and IPv6 addresses.

Alternatively, you can use a natural sort algorithm. This will not verify the addresses and may be incorrect, but works as long as you input is always IPv4 addresses in the form 1.2.3.4.

Community
  • 1
  • 1
phihag
  • 278,196
  • 72
  • 453
  • 469
3

If you do not want to use any external software and want a compact solution, you can always supply a lambda function as sort key.

with open("ip.txt", "r") as infile:
    iplist = sorted([i.strip() for i in infile.readlines()], key = lambda x: int(''.join((lambda a:lambda v:a(a,v))(lambda s,x: x if len(x) == 3 else s(s, '0'+x))(i) for i in x.split('.'))))

This assumes normal IPv4s in ip.txt separated by a line break.

The resulting iplist ist a sorted list with the IPs. You can also output them to file like this:

with open("ip.txt", "r") as infile:
    iplist = sorted([i.strip() for i in infile.readlines()], key = lambda x: int(''.join((lambda a:lambda v:a(a,v))(lambda s,x: x if len(x) == 3 else s(s, '0'+x))(i) for i in x.split('.'))))

with open("output.txt", "w") as outfile:
    outfile.write("\n".join(i for i in iplist))

The output file could be the same as the input or a different file.

Tristan
  • 1,576
  • 9
  • 12
  • This works great, but how can you remove all the bracketing and quotes and force the output to be a single column with just the IP addresses by themselves? What I'm getting is ['5.6.240.180', '9.2.35.35', '16.166.188.35'] as an example. – Alby Feb 07 '17 at 16:49
  • 1
    @Alby I edited the code with explanations on how to write the result to file again. – Tristan Feb 07 '17 at 17:08
  • Thank you. Now it makes sense. Please help my stackexchange score with an up arrow click if possible. Thanks. – Alby Feb 09 '17 at 18:43