retomar a leitura de um arquivo de log a partir do ponto em que o deixei da última vez

retomar a leitura de um arquivo de log a partir do ponto em que o deixei da última vez

Eu tenho um arquivo de log que é atualizado continuamente (nova linha adicionada) após algum período de tempo.

Estou buscando apenas mensagens de erro do arquivo a cada 10 minutos.

Inicialmente, na primeira vez, busquei todas as linhas em um novo arquivo com um padrão correspondente "ERROR FOUND" usandoestranho.

Mas depois de 10 minutos, mais uma nova linha foi adicionada a um arquivo de log, então quero ler esse arquivo de log de onde deixei. Não quero começar do início novamente.

Alguém pode me sugerir o melhor código ou script para isso?

Responder1

Se você abrir o arquivo em um descritor de arquivo como:

exec 3< /path/to/log/file

Você pode então processá-lo:

awk '...' <&3

Depois disso, fd 3 apontará para onde awko deixou.

10 minutos depois, a partir da mesma invocação do shell, você pode executar isso

awk '...' <&3

comando novamente para processar os novos dados.

Se você quiser salvar a posição em que estava, para poder retomar a leitura de uma invocação de shell diferente, com ksh93, você pode fazer:

#! /usr/bin/env ksh93
file=/path/to/some-file
offset_file=$file.offset

exec 3< "$file"
[ -f "$offset_file" ] && exec 3<#(($(<"$offset_file")))

awk '...' <&3

echo "$(3<#((CUR)))" > "$offset_file"

Ou com zsh:

#! /usr/bin/env zsh

zmodload zsh/system
file=/path/to/some-file
offset_file=$file.offset

exec 3< $file
[ -f "$offset_file" ] && sysseek -u 3 "$(<$offset_file)"

awk '...' <&3

echo $((systell(3))) > $offset_file

Responder2

Gosto da resposta do Stéphane porque ele não lê o arquivo inteiro repetidas vezes, então adiciono aqui ofesta(no Linux) equivalente à sua solução (o bash não tem recursos internos seekou tellhabilidades). Eu teria usado um comentário, mas minha reputação é muito baixa.

LASTPOS=/tmp/saved_pos

exec 3< "$1"
test -f "$LASTPOS" && STARTPOS=$(($(<$LASTPOS)+1))
tail -c "+${STARTPOS:-1}" <&3 | grep "ERROR FOUND"
grep '^pos:' /proc/self/fdinfo/3 | cut -f2 > "$LASTPOS"

Também substituí o awkcomando por a grepporque geralmente é mais rápido. Você pode canalizar a saída para um awkcomando se precisar de processamento adicional.

Responder3

Eu tentaria com wc -le tail.
Se você estiver usando o bash, isso deve funcionar:

#!/bin/bash
LASTLNFILE=/tmp/lastline     # replace with a suitable path
test -f $LASTLNFILE && LASTLN=$(<$LASTLNFILE)
CURLN=$(wc -l $1 | cut -d' ' -f1)

if ((CURLN-LASTLN > 0)); then
  tail -n $((CURLN-LASTLN)) $1
fi
echo $CURLN > $LASTLNFILE

PS use-o como um filtro antes do seu programa awk, por exemplo (assumindo que você o nomeou 'newlines.sh'):

./newlines.sh <log_file> | awk -f <your_awk_program>`

Estou deixando o script acima como um exemplo de comonão faça isso. Logo depois de escrevê-lo, percebi que ele é vulnerável a uma condição de corrida, sempre que o arquivo de log é atualizado enquanto o script está em execução.

Uma abordagem AWK pura é preferível:

#!/bin/awk

BEGIN { 
  lastlinefile = "/tmp/lastlinefile"
  getline lastline < lastlinefile
}

NR > lastline && /ERROR FOUND/ {
  # do your stuff...
  print
}

END { print NR > lastlinefile }

informação relacionada