retomar a leitura de um arquivo de log do ponto em que o deixei pela última vez [duplicado]

0

Eu tenho um arquivo de log que está continuamente atualizando (nova linha adicionada) após um curto período de tempo.

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

Inicialmente, na primeira vez, obtive toda a linha em um novo arquivo com um padrão correspondente "ERROR FOUND" usando awk .

Mas depois de 10 minutos, mais uma nova linha foi adicionada a um arquivo de log, por isso quero ler esse arquivo de log de onde saí. Eu não quero começar do começo de novo.

Qualquer corpo pode me sugerir melhor código ou script para isso?

    
por Vipin Sahu 29.08.2018 / 08:53

3 respostas

2

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

exec 3< /path/to/log/file

Você pode processá-lo:

awk '...' <&3

Depois disso, o fd 3 apontará para onde awk o deixou.

10 minutos depois, a partir da mesma invocação de 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 chamada 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
    
por 29.08.2018 / 11:36
1

Eu gosto da resposta do Stéphane porque ele não lê o arquivo inteiro de novo e de novo, então eu adiciono aqui o bash (no Linux) equivalente à sua solução (o bash não possui o seek ou tell capacidade). 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"

Eu também substituí o comando awk por grep porque geralmente é mais rápido. Você pode canalizar a saída para um comando awk se precisar de processamento adicional.

    
por 29.08.2018 / 16:27
0

Eu tentaria com wc -l e 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

P.S. use-o como um filtro antes do seu programa awk, por ex. (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 como não fazer isso . Logo depois de escrevê-lo, percebi que é vulnerável a uma condição de corrida, sempre que o arquivo de log é atualizado enquanto o script está sendo executado.

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 }
    
por 29.08.2018 / 10:00