Estou tentando obter algumas estatísticas triviais sobre alguma saída de depuração.
Cada linha de depuração tem o formato(class name)(delimiter 1)(object ID)(delimiter 2)(method name)(delimiter 3)(log message)
Quero contar quantas linhas vêm de quais métodos.
Essencialmente, se cada linha puder ser reduzida para (class name)(delimiter)(method name)
, quero saber quantas ocorrências de cada uma dessas reduções aparecem no arquivo de log.
Qual comando posso executar no Bash para fazer a contagem?
(Estou fazendo isso no macOS com macports substituindo a maioria das ferramentas padrão do estilo BSD por ferramentas GNU.)
Posso extrair o nome da classe com grep -o -E "^.*(delimiter 1)
, ou extrair o nome do método com grep -o -E "(delimiter 2).*(delimiter 3)"
, ou destacar ambos com grep --color=always -E "^.*(delimiter 1)|(delimiter 2).*(delimiter 3)"
. Fiquei preso procurando uma maneira de grep
produzir apenas as duas partidas que poderiam ser analisadas | uniq -c
para fazer a contagem.
Existe uma maneira de grep
imprimir ambas as correspondências para cada linha, em vez de apenas uma correspondência ou a linha inteira?
Responder1
Em essência, isso pode ser feito com
sed -r -n 's/(^.*)(delimiter 1)(.*)(delimiter 2)(.*)(delimiter 3)(.+$)/\1(delimiter)\5/p' <( command that generates debug logs ) | sort | uniq -c | sort -rn
(adaptado deaqui)
.*
pode combinar demais;sed
é ganancioso e deseja combinar o máximo possível o mais cedo possível, portanto, talvez seja necessário, por exemplo, negações dos delimitadores (o que pode ser complicado se você tiver delimitadores inconvenientes)- Ir de
^
para$
é importante, se sua expressão não corresponder à linha inteira,sed
incluirá a parte sem correspondência na saída - Parênteses são necessários apenas em torno do nome da classe e do método; remover os outros significa alterar os números no final, porque os números se referem a subexpressões entre parênteses em ordem. (Incluir todos eles torna possível mostrar mais do que está acontecendo na
sed
saída, por exemplo, alterando o final para/\1(delimiter)\5 -- \1\2\3\4\5\6\7/p
) sort
tem que ser executado antesuniq -c
porqueuniq -c
apenas conta execuções de linhas idênticas consecutivas, linhas idênticas não consecutivas obtêm contagens separadasuniq -c
não pode ser substituídosort -u
porquesort -u
apenas descarta duplicatas e não as conta- A final
sort
não é necessária para responder à pergunta feita - Sim, se você usa expressões regulares para resolver um problema, agora você tem dois problemas.