Сортировка IP-адресов

Обычная сортировка IP-адресов ломает порядок? Разберёмся, почему так, и приручим маски подсетей. Вас ждут готовые решения для Python, Bash, MySQL, Excel и PowerShell!

Бесплатная консультация юриста

+7 (800) -02-87-29

Реклама jurik.ru

В сети любой специалист сталкивается с задачей упорядочить список IP‑адресов. На первый взгляд кажется, что достаточно применить обычную сортировку строк, но в реальности такой подход приводит к ошибкам: 10.11.2.1 окажется после 10.11;100.1 и т.д. В статье разберём, почему так происходит, как работают маски подсетей (/24, /16 и др.), а также представим готовые решения для самых популярных сред: Python, Bash, MySQL, Excel, PowerShell.


Почему обычная строковая сортировка не подходит?

IP‑адрес в традиционной записи состоит из четырёх октетов, разделённых точками:

AAA.BBB.CCC.DDD

При лексикографической (строковой) сортировке сравниваются символы слева направо. Поэтому строка 10.11.100.1 считается «меньше», чем 10.11.2.1, потому что символ 1 (из 100) меньше 2. Чтобы получить корректный порядок, каждый октет необходимо сравнивать как целое число.

Запомните: правильная сортировка IP‑адресов – это сортировка по четырём числам, а не по строке.

Маски подсетей и их роль в сортировке

Маска подсети определяет, какие биты IP‑адреса относятся к сети, а какие – к хосту. Записывается в виде /N, где N – количество «единичных» битов слева.

  • /32 – 255.255.255.255 – один единственный адрес.
  • /24 – 255.255.255.0 – 8 битов под хосты (256 адресов).
  • /16 – 255.255.0.0 – 16 битов под хосты (65 536 адресов).
  • … и т.д..

Пример: сеть 192.168.0.0/24 охватывает диапазон от 192.168.0.0 до 192.168.0.255. При сортировке внутри такой подсети порядок будет определяться только последним октетом, но если в списке присутствуют адреса из разных подсетей (/24, /16), то необходимо учитывать все четыре октета.


Алгоритм «правильной» сортировки

  1. Разбить каждый адрес на четыре части.
  2. Преобразовать каждую часть в целое число.
  3. Сравнивать адреса последовательно: первый октет → второй → третий → четвёртый.
  4. Опционально: преобразовать адрес в 32‑битное целое (uint32) и сортировать уже его.

Последний пункт особенно удобен, когда нужно быстро сравнивать большие массивы (десятки‑сотни тысяч записей).


Практические решения

Bash / Linux (команда sort -t . -k1,1n -k2,2n -k3,3n -k4,4n)

# Пример файла ip.txt
10.11.10.11
10.11.10.222
10.11.12.13
10.11.102.3

sort -t . -k1,1n -k2,2n -k3,3n -k4,4n ip.txt

Опция -t . задаёт разделитель, а -kX,Xn указывает числовую сортировку по X‑му полю.

Python (модуль ipaddress)

import ipaddress

ips = [
 "10.11.10.11",
 "10.11.10.222",
 "10.11.12.13",
 "10.11.102.3"
]

sorted_ips = sorted(ips, key=ipaddress.IPv4Address)

print("
".join(sorted_ips))

Библиотека ipaddress входит в стандартный набор Python 3, поэтому дополнительных установок не требуется.

MySQL / MariaDB

Для сортировки IP‑адресов в запросе используют функцию INET_ATON, которая переводит строку в 32‑битное целое.

SELECT ip
FROM devices
ORDER BY INET_ATON(ip);

Если необходимо получить обратно строковое представление, используйте INET_NTOA.

Excel

Самый простой способ – добавить вспомогательный столбец, где IP‑адрес переводится в десятичный вид:

  1. Допустим, адрес в ячейке A2.
  2. В ячейку B2 введите формулу:
    =SUMPRODUCT(TEXTSPLIT(A2,".")*{16777216;65536;256;1}) (Excel 365)
    Для более старых версий используйте комбинацию LEFT, MID, RIGHT и VALUE.
  3. Скопируйте формулу вниз, затем сортируйте по столбцу B.

После сортировки столбец B можно скрыть.

PowerShell

# Список IP‑адресов
$ips = @(
 '10.11.10.11',
 '10.11.10.222',
 '10.11.12.13',
 '10.11.102.3'
)

$sorted = $ips | ForEach-Object { [System.Net.IPAddress]::Parse($_) } |
 Sort-Object

$sorted | ForEach-Object { $_.ToString }

Тип IPAddress реализует сравнение по числовому значению, поэтому сортировка «из коробки» работает корректно.


Сортировка больших наборов (пример ≈ 2416 записей)

В реальных проектах часто требуется обработать несколько тысяч IP‑адресов. Ниже – рекомендации, как обеспечить эффективность.

  • Преобразование в 32‑битные числа – экономит память и ускоряет сравнение. В Python это int(ipaddress.IPv4Address(addr)), в Bash – printf "%u
    "
    после awk.
  • Использование внешних сортировщиков (например, sort -u в Linux) позволяет работать с файлами, превышающими объём ОЗУ.
  • Индексация в базах данных – храните IP как INT UNSIGNED и создавайте индекс. Сортировка будет происходить за O(log N).
  • Параллельная обработка – в Python можно воспользоваться multiprocessing.Pool для конвертации, а затем объединить результаты.

Пример скрипта, который читает файл ips.txt (≈ 2416 строк), преобразует адреса в числа, сортирует и выводит обратно в привычный формат:

#!/usr/bin/env python3
import ipaddress, sys

def main(path):
 with open(path) as f:
 # Читаем, убираем пробелы и переводим в целые числа
 nums = [int(ipaddress.IPv4Address(line.strip)) for line in f if line.strip]
 # Сортируем
 nums.sort
 for n in nums:
 print(str(ipaddress.IPv4Address(n)))

if __name__ == '__main__':
 if len(sys.argv) != 2:
 print('Usage: sort_ips.py ', file=sys.stderr)
 sys.exit(1)
 main(sys.argv[1])

Скрипт обрабатывает любой объём данных, ограниченный лишь доступной памятью (для 2416 записей это менее 1 МБ).


Часто задаваемые вопросы

Что делать, если в списке есть смешанные IPv4 и IPv6?

Разделите их на два списка и сортируйте отдельно. Для IPv6 используйте ipaddress.IPv6Address (Python) или INET6_ATON (MySQL).

Как сортировать диапазоны (CIDR), а не отдельные адреса?

Сначала «разворачиваем» диапазоны в отдельные адреса (если нужно), либо сортируем по начальному адресу сети и длине маски. В Python:

import ipaddress
net = ipaddress.ip_network('192.168.0.0/24')
print(int(net.network_address), net.prefixlen) # (3232235520, 24)

Почему sort -n иногда «ломает» порядок?

Опция -n сравнивает только первую найденную числовую последовательность. При IP‑адресах нужно явно указать, какие поля сравнивать (-k1,1n -k2,2n …).


Сортировка IP‑адресов – задача, требующая внимания к деталям:

  • Разбивать адреса на октеты и сравнивать их как числа.
  • Для больших наборов удобно переводить адрес в 32‑битное целое.
  • В разных средах существуют готовые функции (ipaddress, INET_ATON, System.Net.IPAddress), которые делают работу безопасной и быстрой.

Следуя рекомендациям из этой статьи, вы сможете безошибочно упорядочить любые списки – от десятков до десятков‑тысяч записей, включая «2416‑элементный» набор, о котором шла речь в заголовке.


Дата публикации:  г. | Автор: виртуальный помощник ChatGPT