Adiciona mtime ao grep -c output e classifica a saída por mtime

3

Eu tenho um diretório cheio de registros nomeados no seguinte estilo:

info.log00001
info.log00002
info.log00003
...
info.log09999
info.log


Minha saída atual (usando grep -c)

Eu preciso analisar a frequência de um erro específico que acontece ocasionalmente, então vá para esse diretório e use grep -crw . -e "FooException BarError" | sort -n | less para obter algo como:

./info.log00001: 1
./info.log00002: 0
./info.log00003: 42
...
./info.log09999: 25
./info.log: 0

Então, posso ls -lt ver a data de modificação deles e analisar quando o erro aconteceu mais.


Minha saída desejada (com contagem e data)

De qualquer forma, gostaria de encontrar uma maneira de obter uma saída com a contagem e a data na mesma linha. Isso tornaria minha análise mais fácil. Eu gostaria de algo como:

2015-09-31 10:00 ./info.log00001: 1
2015-09-31 10:15 ./info.log00002: 0
2015-09-31 10:30 ./info.log00003: 42
...
2016-04-01 13:20 ./info.log09999: 25
2015-09-31 13:27 ./info.log: 0


Informações adicionais

Idealmente, eu gostaria de realizar isso com apenas um comando, mas primeiro lançando a saída de grep para um arquivo e depois processando esse arquivo também.

Além disso, eu realmente não me importo com o formato da data ou se a data está no final ou no começo da linha. Tudo o que eu quero é ter os arquivos classificados por data começando com o mais antigo (que também é o arquivo com o menor número em seu nome)

Eu encontrei uma maneira de realizar algo parecido com awk , mas no meu caso não funcionaria, já que analisa o nome do arquivo da saída de grep e, no meu caso, a saída de grep tem mais texto que apenas o caminho para o arquivo.

Eu realmente aprecio qualquer feedback sobre isso.

    
por Sam 01.04.2016 / 18:42

3 respostas

5

Se você tem gnu find - e supondo que nenhum dos seus nomes de arquivo contenha novas linhas - você pode usar o find para mostrar o -printf no formato desejado + o nome do arquivo, em seguida, execute mtime para obter a contagem:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM %p: ' -exec grep -cw "whatever" {} \; | sort -k1,1 -k2,2

Como alternativa, com grep , você poderia glob e classificar por tempo de modificação (via qualifiers - zsh seleciona arquivos regulares, . ordena em ordem decrescente por mtime ) e, em seguida, para cada arquivo imprime Om usando o mtime , o nome do arquivo e, novamente, obtém a contagem via stat :

zmodload zsh/stat
for f in ./**/*(.Om)
do
printf '%s %s\t%s %s: ' $(zstat -F '%Y-%b-%d %H:%M' +mtime -- $f) $f
grep -cw "whatever"  $f
done
    
por 01.04.2016 / 19:32
3

Uma construção bash

shopt -s globstar
join -o 1.2,0,2.2 -t$'4' <(stat -c $'%n4%y' ** | sort) \
                            <(grep -crw "..." | sort | sed -r $'s/:([^:]*)/4\1/') \
                             | tr '4' '\t'

Há algumas coisas funky lá com 4 - esse é o valor octal para o caractere FS . É concebível que você tenha nomes de arquivos existentes com aquele caractere no nome, você pode alterar o caractere delimitador se precisar.

O comando stat exibe o nome do arquivo e o tempo modificado para cada arquivo de forma recursiva.

Você está familiarizado com o comando grep. Eu traduzo os últimos dois pontos para o char do FS.

Eu tenho que usar a sintaxe de cotação ANSI-C do bash para stat e sed para obter o caracter do FS lá.

O comando join une a saída de stat com o do grep e gera a saída "data FS nome do arquivo FS count"

Depois eu traduzo o FS para uma guia simples.

    
por 01.04.2016 / 19:25
3

Solução baseada em Perl:

perl -lne 'if ($.==1) {
 print localtime($t)." $f: $c\n" if defined $t; 
 $c=0; $f=$ARGV; $t=(stat($f))[7];} $c++ if /$expr/o; 
} BEGIN { $expr=shift @ARGV; push @ARGV,"/etc/hosts"; 
' "search-expression" info.log

Nota: não testado.

Algum truque padrão do perl aqui. -n envolve while (<>) { em torno do seu código. Quando $. é 1, é um novo arquivo. Se tivermos processado um arquivo, imprimamos as informações de resumo - timestamp, filename, count. Agora, somente para a primeira linha, obtenha o nome do arquivo atual, o registro de data e hora do arquivo mtime e redefina o contador. Para cada linha, incremente o contador se corresponder à expressão regular desejada. Finalize o loop while e inicie algum código de iniciação, que é executado antes do bloco anterior. Tome o primeiro argumento como o regex para combinar em cada linha. Agora, para a lista de argumentos, remova o primeiro argumento. Em seguida, anexe um arquivo fictício à lista arg que acionará a expressão print final. É um truque inofensivo.

    
por 01.04.2016 / 19:43