Альтернатива uniq -c и сортировка в чистом awk

Вот одна команда, используемая для фильтрации из файла access.log количества обращений по IP-адресу, а затем подсчета количества обращений для каждого IP-адреса и сортировки их от наименьшего к наибольшему количеству:

awk '{print $1}' "${ACCESSLOG}" | sort -n | uniq -c | sort -nk1

и вот выдержка из результата:

 26 45.59.193.115
 26 74.125.63.33
 27 88.156.36.194
 28 12.208.4.156
 29 12.208.4.156
 31 98.236.117.199
 32 176.9.82.6
 33 187.34.167.111
 35 67.110.83.252
 37 54.184.4.183
 39 195.59.2.173
 39 70.199.109.118
 44 12.208.4.156
 59 88.156.36.194

Теперь можно ли получить тот же результат, используя только awk? Нет uniq -c, нет сортировки.

Не могу найти много информации в Интернете об этом...


person Jeanmichel Cote    schedule 21.07.2015    source источник
comment
Что это последнее uniq дает вам?   -  person Etan Reisner    schedule 21.07.2015
comment
Я думаю, что OS X/bsd awk означает, что вы можете выполнять сортировку в awk вручную или использовать sort для awk-unique-ified вывода.   -  person Etan Reisner    schedule 21.07.2015


Ответы (3)


Теоретически - да, можно. Но здесь две части:

Можете ли вы реализовать sort и uniq? Сортировка будет довольно сложной, но, конечно, вы можете реализовать что угодно в awk. Uniq должен быть тривиальным.

Можете ли вы реализовать свой конвейер, так что именно | uniq -c | sort -nk1 | uniq. Да, и это будет не очень сложно. Просто используйте что-то вроде:

awk '{ips[$1]++} END {for (ip in ips) { print ips[ip], ip}}'

Это делает подсчет/уникальную часть. Вам нужно будет добавить asort для сортировки записей в конце.

person viraptor    schedule 21.07.2015
comment
Вам не нужно if, чтобы числа считались правильно. Несуществующие значения awk по умолчанию равны 0, поэтому вы можете просто ++ на запись в массиве ips, и ваш счет сработает. - person Etan Reisner; 21.07.2015
comment
Спасибо @EtanReisner, это полезно! - person viraptor; 21.07.2015
comment
asort реализован с помощью gawk, а не awk. - person Jeanmichel Cote; 21.07.2015

В GNU awk есть функция, упрощающая подсчет и сортировку:

awk 'BEGIN{PROCINFO["sorted_in"]="@val_num_asc"} { a[$1]++ } END{for (ip in a)print a[ip],ip}' access.log

Оператор PROCINFO["sorted_in"]="@val_num_asc" заставляет массив упорядочиваться по значению, а не по ключу, в возрастающем числовом порядке.

(AWK по умолчанию в Mac OSX — это BSD, поэтому не пытайтесь делать это там.)

Пример

Предположим, что у нас есть входной файл:

$ cat access.log
74.125.63.33
45.59.193.115
45.59.193.115
74.125.63.33
74.125.63.33
74.125.63.33
195.59.2.173

Затем вышеизложенное производит:

$ awk 'BEGIN{PROCINFO["sorted_in"]="@val_num_asc"} { a[$1]++ } END{for (ip in a)print a[ip],ip}' access.log
1 195.59.2.173
2 45.59.193.115
4 74.125.63.33
person John1024    schedule 21.07.2015
comment
@JeanmichelCote, вы можете установить gawk в своей системе. К сожалению, такие вещи, как FPAT, работают только с gawk. - person Registered User; 21.07.2015
comment
Итак, я добрался до своего Linux-сервера, чтобы попробовать, и на самом деле ваша команда работает нормально, но немного медленнее, чем awk-команда @viraptor. реальный 0m0.014s - пользователь 0m0.000s - система 0m0.008s против реального 0m0.008s - пользователь 0m0.004s - система 0m0.008s - person Jeanmichel Cote; 21.07.2015

@viraptor На самом деле, я исправил свою команду, потому что оба наших результата были разными, и теперь это выглядит примерно так:

awk '{print $1}' "${ACCESSLOG}" | sort -n | uniq -c | sort -nk1

реальное 0м0.020с

пользователь 0м0.016с

система 0m0.012s

Итак, я добавил команду sort к вашему первоначальному предложению, потому что я не могу использовать ни gawk (asort), ни GNU:

awk '{if(ips[$1]) {ips[$1]++} else {ips[$1]=1}} END {for (ip in ips) { print ips[ip], ip}}' "$ACCESSLOG" | sort -nk1

реальное 0м0.019с

пользователь 0м0.004с

система 0m0.008s

В то время как ваша рефакторинговая команда:

awk '{ips[$1]++} END {for (ip in ips) { print ips[ip], ip}}' "${ACCESSLOG}" | sort -nk1

реальное 0м0.014с

пользователь 0м0.004с

система 0m0.012s

Интересно сравнить скорости...

person Jeanmichel Cote    schedule 21.07.2015