Como posso contar o número de vezes que uma frase aparece em um arquivo e formatá-lo corretamente?

3

Eu tenho um arquivo de log do qual estou tentando extrair dados. Ele é formatado assim e lista quando certos módulos são registrados:

19:50:26 (license_manager) OUT: "certain_module" [email protected]
19:50:28 (license_manager) IN: "rarely_used_module" [email protected]
19:50:28 (license_manager) IN: "certain_module" [email protected]
19:50:28 (license_manager) IN: "different_module" [email protected]
19:50:38 (license_manager) OUT: "certain_module" [email protected]
19:50:38 (license_manager) OUT: "different_module" [email protected]

Até agora eu tenho o seguinte. Estou interessado especificamente em saber quando o "rare_used_module" está sendo verificado e por quem:

cd /path/to/script && cat logfile.txt | grep -c "rarely_used_module" 

Isso só me dá a conta, e nada mais. Eu gostaria de tornar isso mais sofisticado por dois motivos: para aprender mais sobre shell scripts e para implementar uma maior quantidade de conceitos bash neste script, em segundo lugar, eu gostaria que ele fosse capaz de me dizer a que horas a licença foi verificada. e qual usuário verificou.

A situação ideal absoluta seria contar o número de vezes que esta licença foi verificada e formatá-la em algum tipo de tabela para referência. Isso é possível?

Atualização 1

Saída desejada, algo como o seguinte. Vou apresentar um exemplo teórico abaixo em que o rare_used_module foi verificado 4 vezes por 2 usuários únicos, 2 vezes separadas:

Number of license checkouts for rarely_used_module: 4 
User : [email protected] (2)
User : [email protected] (2)

Essencialmente, quero o número de vezes que o módulo foi retirado, total, e quero os nomes dos usuários que verificaram essa licença. Eu sei que posso pegar a linha OUT: para "rare_used_module", mas não tenho certeza de como fazer isso.

    
por user117058 27.05.2015 / 23:31

2 respostas

1

Para sua pergunta atualizada:

awk '
/"rarely_used_module"/ && /OUT:/ { nc[$NF]++ ; c++ }
END {
    printf "Number of license checkouts for rarely_used_module: %d\n", c
    for (i in nc) printf "User: %s (%d)\n", i, nc[i]
}
' logfile.txt

cria esta saída:

Number of license checkouts for rarely_used_module: 4
User: [email protected] (2)
User: [email protected] (2)


Eu mantenho a resposta original abaixo, para mostrar como estender o código caso você tenha requisitos maiores.

Aqui está um exemplo de como se pode abordar essas tarefas usando awk :

awk '
BEGIN { SUBSEP = ", " ; OFS = ": " }
{ m[$(NF-1)]++ }
{ n[$(NF-1)] = n[$(NF-1)] " " $NF }
{ nc[$(NF-1),$NF]++ }
END {
    print "\n=== count modules:"
    for (i in m) print i, m[i]
    print "\n=== collect names using modules:"
    for (i in n) print i, n[i]
    print "\n=== count names using modules:"
    for (i in nc) print i, nc[i]
}
' logfile.txt

Explicação:

  • { m[$(NF-1)]++ } - incrementa o contador para o segundo último campo (módulos) nos dados de entrada
  • { n[$(NF-1)] = n[$(NF-1)] " " $NF } - concatena o último campo (nomes) para cada chave (módulos)
  • { nc[$(NF-1),$NF]++ } - incrementa o contador para uma tupla-chave de (nome, módulo)

Com seus dados de exemplo, ele produziria essa saída:

=== count modules:
"rarely_used_module": 1
"different_module": 2
"certain_module": 3

=== collect names using modules:
"rarely_used_module":  [email protected]
"different_module":  [email protected] [email protected]
"certain_module":  [email protected] [email protected] [email protected]

=== count names using modules:
"different_module", [email protected]: 1
"different_module", [email protected]: 1
"certain_module", [email protected]: 2
"rarely_used_module", [email protected]: 1
"certain_module", [email protected]: 1
    
por 28.05.2015 / 00:08
0

Quando eu preciso de algo mais complexo do que alterar ou combinar cada linha, eu uso Python, porque é uma linguagem de propósito geral. Pode ser mais detalhado do que awk (BTW, existe um pawk , awk do Python), mas também fornece código bem documentado e facilmente extensível.

Aqui está o script do Python 2 para sua tarefa:

from collections import defaultdict

FILE = 'module.txt'

# Global table of usages is 
# dict [ module_name ] -> dict [ user_name ] -> count
usage = defaultdict(lambda : defaultdict(int))

# Read, parse data and add usage count where needed
with open(FILE) as f:
    for line in f:
        # Split using spaces and pick last 2 fields, 
        # strip unncessary characters
        fields = line.split()     
        user = fields[-1].rstrip()
        module_name = fields[-2].strip('"')

        usage[module_name][user] += 1

# Now print pretty results
for module_name, module_usage in usage.items():
    print '====> ', module_name
    for user, count in module_usage.items():
        print '\t', user, count

Ele imprimirá os seguintes dados para sua amostra:

====>  different_module                                                                                                                                                        
        [email protected] 1
        [email protected] 1
====>  rarely_used_module
        [email protected] 1
====>  certain_module
        [email protected] 2
        [email protected] 1
    
por 28.05.2015 / 01:55