Предположим, у вас есть файл, который содержит IP-адреса, по одному адресу в каждой строке:
10.0.10.1
10.0.10.1
10.0.10.3
10.0.10.2
10.0.10.1
Вам нужен сценарий оболочки, который подсчитывает для каждого IP-адреса, сколько раз он появляется в файле. Для предыдущего ввода вам понадобится следующий вывод:
10.0.10.1 3
10.0.10.2 1
10.0.10.3 1
Один из способов сделать это:
cat ip_addresses |uniq |while read ip
do
echo -n $ip" "
grep -c $ip ip_addresses
done
Однако это действительно далеко не эффективно.
Как бы вы решили эту проблему более эффективно, используя bash?
(Следует добавить: я знаю, что это можно решить с помощью perl или awk, меня интересует лучшее решение для bash, а не для этих языков.)
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:
Предположим, что исходный файл имеет 5 ГБ, а машина, на которой работает алгоритм, имеет 4 ГБ. Так что сортировка не является эффективным решением и не читает файл более одного раза.
Мне понравилось решение, похожее на хеш-таблицу - кто-нибудь может предложить улучшения для этого решения?
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ № 2:
Некоторые люди спрашивали, зачем мне это делать в bash, когда это проще, например, в perl. Причина в том, что на машине, которую я должен был сделать, этот Perl был недоступен для меня. Это была специально созданная машина Linux без большинства инструментов, к которым я привык. И я думаю, что это была интересная проблема.
Поэтому, пожалуйста, не вините вопрос, просто проигнорируйте его, если он вам не нравится. :-)
Ответы:
Сначала будет напечатан счетчик, но в остальном он должен быть именно тем, что вы хотите.
источник
sort ip_addresses | uniq -c | sort -nr
sort ip_addresses | uniq -c | sort -nr | awk '{ print $2, $1 }'
получить IP-адрес в первом столбце и считать во втором.sort -nr -k1,1
Быстрый и грязный метод заключается в следующем:
cat ip_addresses | sort -n | uniq -c
Если вам нужно использовать значения в bash, вы можете назначить всю команду переменной bash, а затем просмотреть результаты.
PS
Если команда сортировки опущена, вы не получите правильные результаты, так как uniq просматривает только последовательные идентичные строки.
источник
для суммирования нескольких полей на основе группы существующих полей используйте приведенный ниже пример: (замените $ 1, $ 2, $ 3, $ 4 в соответствии с вашими требованиями)
источник
sort
иuniq
проще всего делать подсчет, но не помогает, когда вам нужно вычислить / суммировать значения полей. Синтаксис массива awk очень мощный и ключевой для группировки здесь. Спасибо!print
функции , кажется, 64 бит вниз по шкале целых чисел до 32 бит, так что для ИНТ значений , превышающих 2 ^ 31 вы можете использоватьprintf
с%.0f
форматом вместоprint
тамarr[$1,$2]+=$3+$4
например, наarr[$1,$2]=(arr[$1,$2] $3 "," $4). I needed this to provide a grouped-by-package list of files (two columns only) and used:
arr [$ 1] = (arr [$ 1] $ 2) `с успехом.Каноническое решение упомянуто другим респондентом:
Это короче и более кратко, чем то, что можно написать на Perl или awk.
Вы пишете, что не хотите использовать сортировку, потому что размер данных больше размера основной памяти машины. Не стоит недооценивать качество реализации команды сортировки Unix. Сортировка использовалась для обработки очень больших объемов данных (например, исходных данных биллинга AT & T) на машинах с 128 КБ (это 131 072 байта) памяти (PDP-11). Когда сортировка встречает больше данных, чем предварительно установленный предел (часто настраиваемый близко к размеру основной памяти машины), она сортирует данные, прочитанные в основной памяти, и записывает их во временный файл. Затем он повторяет действие со следующими порциями данных. Наконец, он выполняет сортировку слиянием этих промежуточных файлов. Это позволяет сортировке работать с данными, во много раз превышающими основную память машины.
источник
эта команда даст вам желаемый результат
источник
Похоже, вам нужно либо использовать большой объем кода для имитации хэшей в bash, чтобы получить линейное поведение, либо придерживаться
квадратичныхсуперлинейных версий.Среди этих версий решение saua является лучшим (и самым простым):
Я нашел http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2005-11/0118.html . Но это ужасно чертовски ...
источник
Решение (сгруппировано как mysql)
результат
источник
Вы, вероятно, можете использовать саму файловую систему в качестве хеш-таблицы. Псевдокод выглядит следующим образом:
В конце концов, все, что вам нужно сделать, это просмотреть все файлы и распечатать имена и номера файлов в них. В качестве альтернативы, вместо сохранения счетчика, вы можете каждый раз добавлять к файлу пробел или символ новой строки и, в конце концов, просто смотреть на размер файла в байтах.
источник
Я чувствую, awk ассоциативный массив также удобен в этом случае
Группа по почте здесь
источник
Большинство других решений считают дубликаты. Если вам действительно нужно сгруппировать пары ключ-значение, попробуйте это:
Вот мой пример данных:
Это напечатает пары ключ-значение, сгруппированные по контрольной сумме md5.
источник
чистый удар (без вилки!)
Есть способ, используя ударфункция . Этот путь очень быстрый, так как нет вилки! ...
... Пока куча ip адресов остается маленькой !
Примечание. IP-адреса преобразуются в 32-разрядное целое число без знака, используемое в качестве индекса для массива . Это использует простые массивы bash , а не ассоциативный массив (который дороже)!
На моем хосте это происходит намного быстрее, чем при использовании вилок, примерно до 1000 адресов, но занимает около 1 секунды, когда я попытаюсь отсортировать не более 10 тысяч адресов.
источник
Я бы сделал это так:
но Uniq может работать для вас.
источник
Я понимаю, что вы ищете что-то в Bash, но в случае, если кто-то еще ищет что-то в Python, вы можете рассмотреть это:
Поскольку значения в наборе уникальны по умолчанию, и Python довольно хорош в этом, вы можете выиграть что-то здесь. Я не проверял код, поэтому он может быть ошибочным, но это может привести вас к этому. И если вы хотите считать события, легко использовать dict вместо набора.
Редактировать: я паршивый читатель, поэтому я ответил неправильно. Вот фрагмент кода с указанием количества событий.
Словарь mydict теперь содержит список уникальных IP-адресов в качестве ключей и количество раз, которое они встречались в качестве их значений.
источник
itertools.groupby()
который в сочетании сsorted()
делает именно то, что просит OP.Сортировка может быть опущена, если порядок не имеет значения
или
если список источников является переменной
источник