2016-01-29 6 views
2

Я делаю сбор данных по массивным файлам журнала, и мне нужно подсчитывать вхождения уникальных строк. Как правило, так это делается с помощью команды:Подсчет вхождений уникальных строк в bash без предварительной сортировки данных

zcat <file> | grep -o <filter> | sort | uniq -c | sort -n 

Что я ищу сделать это не платить штраф производительность сортировки после Grep. Можно ли это сделать, не покидая bash?

ответ

3

Вы можете использовать AWK для подсчета уников и избежать sort:

zgrep -o <filter> <file> | 
awk '{count[$0]++} END{for (i in count) print count[i], i}' 

Также обратите внимание, что вы можете избежать zcat и вызвать zgrep непосредственно.

1

Поскольку вы упомянули, что не хотите покидать bash: вы можете попробовать его с помощью ассоциативных массивов: вы можете использовать входные строки в качестве ключа, а значение count - как значение. Чтобы узнать об ассоциативных массивах, см. Здесь: http://www.gnu.org/software/bash/manual/html_node/Arrays.html.

Но, убедитесь, что для сравнения производительности - тем не менее, вы можете быть лучше использовать сортировку и Uniq или Perl, или ...

+0

Часть мотивации при использовании не сортировки - это также дисковое пространство. У этих хостов очень мало его на не-журнальном диске (который доступен только для чтения). Сортировка удаляет его для больших запросов, поскольку он кэширует его список на диске. Тем не менее, я буду сравнивать результаты. – ralar

1

jq имеет встроенный ассоциативные массивы, так что вы могли бы рассмотреть один из следующие подходы, которые являются одновременно эффективными (например, AWK):

zgrep -o <filter> <file> | 
    jq -nR 'reduce inputs as $line ({}; .[$line] += 1)' 

Это производят результаты в виде объекта JSON с частотами в качестве значений объекта, например,

{ 
    "a": 2, 
    "b": 1, 
    "c": 1 
} 

Если вы хотите, чтобы каждая строка вывода состоит из подсчета и стоимости (в таком порядке), то соответствующий JQ вызов будет:

jq -nRr 'reduce inputs as $line ({}; .[$line] += 1) 
     | to_entries[] | "\(.value) \(.key)"' 

Это будет производить вывод следующим образом:

2 a 
1 b 
1 c 

В jq опции, используемые здесь:

-n # for use with `inputs` 
-R # "raw" input 
-r # "raw" output 
Смежные вопросы