Preciso pesquisar vários arquivos de log (todos os arquivos gerados nas últimas 24 horas, todos mantidos no mesmo diretório) para encontrar a última ocorrência de uma string. Este é o comando que escrevi:
find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1
Mas isso retorna apenas a última linha de um arquivo. Alguma sugestão sobre como ajustar isso para obter todas as linhas?
bash
shell-script
text-processing
grep
Lokesh
fonte
fonte
Respostas:
Assumindo instalações GNU:
fonte
find
executar comandos em arquivos usando-exec
. Combash -c
, estamos gerando umabash
concha que percorre os arquivos encontrados porfind
e executatac .. | grep -m1 fileprefix
em cada-d" "
com corte. Aspas duplas em vez de simplesfind
comando pode filtrar o prefixo do arquivo; ogrep
não deve ser necessário para isso. Também é surpreendente que a string de pesquisa não apareça nesta resposta.Se tudo estiver em um único diretório, você poderá:
Se esses arquivos forem grandes, pode valer a pena acelerar usando-o
tac
para imprimir o arquivo na ordem inversa (última linha primeiro) e depoisgrep -m1
corresponder à primeira ocorrência. Dessa forma, você evita ter que ler o arquivo inteiro:Ambos assumem que não há diretórios correspondentes
fileprefix
. Se houver, você receberá um erro que pode ser ignorado. Se isso for um problema, verifique apenas os arquivos:Se você também precisar do nome do arquivo impresso, adicione
-H
a cadagrep
chamada. Ou, se o seugrep
não suportar, peça para ele também pesquisar/dev/null
. Isso não altera a saída, mas comogrep
são fornecidos vários arquivos, sempre será impresso o nome do arquivo para cada ocorrência:fonte
tac
. Ele sairá assim que a primeira correspondência for encontrada. Acabei de testar com um arquivo de texto 832M e um padrão encontrado na última linha.grep -m 1 pattern file
ferramenta ~ 7 segundos etac file | grep -m1 pattern
levou0.009
.... funcionará se você tiver o GNU
sed
que suporta a-s
opção eparate files e um POSIXfind
.Você provavelmente deve adicionar os
! -type d
ou-type f
qualificadores, porque tentar ler um diretório não será muito útil, e restringir ainda mais o intervalo a arquivos regulares pode evitar uma leitura pendurada em um arquivo de pipe ou dispositivo serial.A lógica é incrivelmente simples -
sed
sobrescreve seuh
espaço antigo com uma cópia de qualquer linha de entrada que correspondasearchstring
ed
elimina da saída todas as linhas de entrada, exceto a última para cada arquivo de entrada. Quando chega à última linha, elex
altera seus espaços de espera e padrão e, portanto, sesearchstring
foi encontrado durante a leitura do arquivo, a última ocorrência desse tipo será impressa automaticamente para saída, caso contrário, ele grava uma linha em branco. (adicione/./!d
ao final dosed
script, se isso for indesejável) .Isso fará uma única
sed
chamada por alguns arquivos de entrada de 65k - ou qualquer que seja o seuARG_MAX
limite. Essa deve ser uma solução de alto desempenho e é simplesmente implementada.Se você também deseja os nomes de arquivos, dado um GNU recente,
sed
você pode escrevê-los em linhas separadas com oF
comando, ou pode imprimi-losfind
em uma lista separada por lote, acrescentando o-print
primário depois+
.fonte
E se:
A descrição acima fornece uma boa saída com a última ocorrência de uma sequência de pesquisa em cada arquivo, seguida pelo respectivo nome de arquivo após a vírgula (modifique a parte ", $ 1" sob eco para alterar a formatação ou removê-la, se desnecessário). A saída de amostra que pesquisa a string de pesquisa '10' em arquivos com um prefixo de nome "arquivo" é a seguinte:
fonte
Este usa GNU
grep
's-H
e-n
opções para sempre imprimir tanto o nome do arquivo eo linenumber de todas as partidas, então ele classifica pelo nome do arquivo e linenumber, e tubos de TI em awk, que armazena o último jogo para cada arquivo em uma matriz e, eventualmente, impressões isto.Um método de força bruta, mas funciona.
fonte