Como cortar parte do arquivo de log?

18

Eu tenho um arquivo de log de 8 Gb (log de produção do Rails). Eu preciso cortá-lo entre algumas datas (linhas). Qual comando eu poderia usar para fazer isso?

Eric Leschinski
fonte
1
Ei pessoal, essa pergunta é sobre um arquivo grande , então é "Ante up!" .. o tempo importa ... Eu testei o script sed favorito em um arquivo real de 8 GB, com 85904064 linhas (100 caracteres por linha). Eu amo o sed, mas, como está, o script sed verifica o arquivo inteiro, sempre . Isso o torna, em média, duas vezes mais lento que o script awk que sai quando encontrado ... Acho que (?) O script sed pode precisar apenas de aq em vez de d para a segunda expressão ... Os resultados do teste estão aqui: paste .ubuntu.com / 573477 .. Além disso, ele não produz a saída correta .. veja meu comentário no final da resposta do asoundmove.
Peter.O
A nova versão sed do asoundmove havia resolvido o problema de velocidade e agora corresponde à velocidade do awks. e o novo versin agora gera dados corretamente ... veja seus comentários para mais detalhes.
precisa saber é o seguinte
Acabei de notar que você disse "recortar" (o que normalmente significa remover) ... Você realmente quer dizer "recortar" ou quer dizer "copiar"? .... Se você quis dizer "cortar", sedserá fácil.
precisa saber é o seguinte

Respostas:

12

Algo como

sed '1,/last date prior to chunk/d;/first date after chunk/,$d' logfile | tee cut-log | less

tee cut-logpermite ver na tela o que está sendo colocado no arquivo cut-log.

EDITAR:

Para satisfazer os padrões exigentes de fred.bear, aqui está uma solução sed (embora a solução awk seja muito mais bonita):

b=BB; e=EE ;echo -e "AA\nAA\nBB\nBB\nCC\nCC\nDD\nDD\nEE\nEE\nFF\nFF" | sed -n ":b;/$b/b p;n;b b;:p;p;n;/$e/b e;b p;:e;p;n;/$e/b e;q"
asoundmove
fonte
3
@dogbane: sim, sim. Editado. Tenho certeza de que às vezes você escreve menos do que o código ideal, ele merece um comentário tão duro?
asoundmove
1
Nota: Se houver várias linhas consecutivas de 'primeira data' com a mesma data, todas, exceto a primeira, não serão excluídas e serão introduzidas na saída ... apenas algo para estar ciente ... (depende de a situação)
Peter.O
1
... mas, mesmo sendo um profissional do pro-sed ++, acho que esse trabalho em particular está além de seus limites, para qualquer coisa que não seja uma 'ferramenta pessoal'. Aqui está o principal problema que o sed tem nesse caso (o seu e o seu meu .. eu consegui que o sed fizesse o mesmo que o seu .. ele também rodava dentro de 1%) .. de volta ao problema principal .. (que não se aplica ao awk) .... Bug (não corrigível): Em relação a uma data que é válida no escopo do log, mas não está realmente presente no log, no caso do 1º argumento, o sed não imprimirá nada e, no caso do segundo argumento, o sed imprimirá tudo após o primeiro encontro! ... mais ...
Peter.O
1
Outro bug corrigível: é que atualmente corresponde a datas em qualquer linha, incluindo a proteção de dados, mas isso é apenas um ajuste de regex. E para quem quiser usá-lo, talvez você possa comentar que os argumentos agora se referem ao primeiro e últimas datas no intervalo (não -1 e +1) .. e finalmente ... meus "padrões exigentes" não são meus. Sou apenas o mensageiro do pedido orador interrogante ... O usuário vai notar se ele funciona como solicitado, ou não .. Esta tem sido uma grande questão para mim .. eu aprendi muito :) ... e eu feliz saber que isso sedpode corresponder awkà velocidade, e na verdade foi um pouco mais rápido.
precisa saber é o seguinte
6

Para imprimir tudo entre FOO e BAR inclusive, tente:

$ sed -n '/FOO/,/BAR/p' file.txt
dogbane
fonte
1
Nota: Isso só vai imprimir a primeira BAR de uma série de bares consecutivos ...
Peter.O
outra observação ... Grande problema se uma das datas não estiver presente nos dados. Se a última data não estiver presente, o sed continuará emitindo linhas até atingir o EOF.
Peter.O
5

Isso fará o que você deseja ...
Tanto a inclusão quanto a exclusão das datas dos parâmetros são mostradas.

# set Test args
set  2011-02-24  2011-02-26  "junk"

from="$1"
till="$2"
file="$3"

# EITHER ====                              +++++++++  
# Ouptut lines between two parameter dates INCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 >= from) && ($2 <= till) { print $0 ; next }
    ($2 > till) { exit }' "$file"

# OR ========                              ---------
# Ouptut lines between two parameter dates EXCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 > from) && ($2 < till) { print $0 ; next }
    ($2 >= till) { exit }' "$file"

Ele testa uma data (classificada) no campo 2 ... Aqui está um exemplo dos dados de teste

    98  2011-02-05 xxxx
    99  2011-02-05 xxxx
   100  2011-02-06 xxxx
   101  2011-02-06 xxxx

E aqui está o gerador de dados de teste .

Peter.O
fonte
Eu escreveria (pegando o primeiro por exemplo) um pouco mais simples assim: awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
asoundmove
@asoundmove: Sim, isso pode parecer melhor, e é definitivamente mais convencional , mas, na realidade, seu tempo de execução é apenas a duração de uma ifinstrução extra no total (nem mesmo uma por linha), ou seja. o fluxo lógico é efetivamente o mesmo, e a diferença no tempo de execução seria contada em nanossegundos .... A única razão pela qual não usei "else" é que esse é efetivamente meu primeiro awkscript de todos os tempos (além de um dia 4 anos atrás, quando brinquei com alguns exemplos) ... e esse é o primeiro mecanismo de ramificação viável que encontrei ... (e como mencionado. é tão rápido) .. Eu uso generosamente o sedTryq
Peter
Não entendo onde você fornece o nome e o local do arquivo de texto neste método? Alguém pode me ajudar a ver através da minha estupidez
Giles
4

Se no seu arquivo de log você tiver as datas nesse formato YYYY-MM-DD, para encontrar todas as entradas, por exemplo, 10/02/2011, você pode:

grep 2011-02-10 log_file

Agora, digamos, se você deseja localizar as entradas para 2011-02-10 e 2011-02-11, use novamente, grepmas com vários padrões:

grep -E '2011-02-10|2011-02-11' log_file
Barun
fonte
Boa. Ele funciona "como anunciado" :) ... No entanto, grepirá procurar o arquivo inteiro, mesmo se a data gama está no início do arquivo. Em média, isso duplica o tempo de uma pesquisa, quando comparado a "sair após o último item do intervalo" ... Estou apenas me referindo a isso por causa do tamanho do arquivo de 8 GB mencionado na pergunta Os resultados do tempo de grep são quase idênticos ao exemplo sed aqui (1min 58seg). Aqui está o link para os resultados dos meus testes de tempo: paste.ubuntu.com/573477
Peter.O
1

Trabalhar com esse tamanho de arquivo é sempre difícil.

Um caminho a seguir poderia ser dividir esse arquivo em alguns pequenos; para isso, você pode usar o comando split.

split -d -l 50000 ToBigFile.data file_

Mesmo que esteja dividido, você ainda pode trabalhar com o arquivo como se fosse um usando um loop bash for

for f in `ls file_*`; do cat $f; done;

Mas, em vez do gato, você pode usar grep invertido para se livrar de dados indesejados, o que é irrelevante para isso. (ou o tipo de refinamento necessário).

Nesse ponto, você trabalhará apenas com muitos arquivos menores, e os comandos mencionados acima funcionarão em muitos arquivos menores.

E quando terminar, você pode usar um segundo for loop para criar o novo arquivo menor novamente.

for f in `ls file_*`; do cat $f >> NewFile.data ; done;

Atualização Desde que começamos a dividir os dados em vários arquivos, haverá muito trabalho com o disco rígido e isso leva tempo. (Nesta questão, aparentemente, 5min).

Por outro lado, os próximos passos provavelmente seriam mais rápidos.

Portanto, esse método provavelmente não faz sentido para uma operação simples grep, awk, sed, mas se os padrões de pesquisa se tornarem mais complicados, poderão se tornar mais rápidos.

Johan
fonte
3
Johanm, leva awk e sed apenas 1 minuto, em média, para pesquisar um arquivo de log de 8 GB no meu computador e, no mesmo computador, apenas a divisão inicial do arquivo, leva 4min 43seg ... :)
Peter.O
Digamos que você possa reduzir esses tempos de awk e sed em 50% nos arquivos menores. Em seguida, ainda precisamos fazer mais do que 10 desses operação antes de ganhar no tempo total ... Então talvez a divisão de arquivo não é a melhor idéia para algumas regressões ...
Johan
O script awk pode (facilmente) ser modificado para gerar 10 resultados de pesquisa diferentes para 10 arquivos ... em uma única passagem, mas isso atrasaria a leitura enquanto na verdade os relatórios seriam gerados ... Sed também poderia fazer o mesmo, mas como eu Como mencionado nos comentários de asoundmove, o sed falhará se uma data / hora específica não tiver nenhuma entrada no log (por exemplo, você está pesquisando a cada hora) .. Eu uso muito o sed e é extremamente útil, mas tem seus limites ... Aqui está uma FAQ do sed sobre quando usar o sed vs awk. Não concordo necessariamente com tudo, mas posso ver o que eles significam ... sed.sourceforge.net/sedfaq6.html
Peter. O
0
perl -wlne '/^2011-02-24/ .. /^2011-02-25/ and print' log_file
Charlesbridge
fonte
Isso imprimirá apenas a primeira entrada de log para 25/02/2011.
Gilles 'SO- stop be evil'