Imprime 20 linhas de texto anteriores de um certo ponto de um arquivo de texto

0

Atualmente:

Eu sou novo em escrever, ensinando a mim mesmo enquanto eu vou e este é o meu primeiro script que estou desenvolvendo. O que meu script está tentando fazer é olhar para o arquivo especificado, digitalizar o arquivo para encontrar a palavra "Erro". Atualmente, ele imprime o restante do arquivo do ponto "ERROR" em um arquivo de saída.

Problema:

Depois de encontrar a palavra "ERRO" em um arquivo, como posso imprimir as 20 linhas anteriores do texto da palavra "ERROR" para um arquivo de saída e acrescentar o resto do arquivo do ponto "ERROR" para o mesmo arquivo de saída?

Solução possível?

Eu usaria algum tipo de loop aqui para fazer isso? Eu tenho o código sudo = na minha cabeça como fazer isso pode funcionar, mas não sei como realmente implementar isso. Alguém pode me aconselhar ou me dizer se existe uma maneira melhor de fazer isso?

Script:

my $file_handle = IO::File->new ('output','a') or die;

print $file_handle "*****************************\n";

while(<>) {

        print $file_handle $_ if(/.*ERROR/ .. /^XXX/);

        }
    
por Peter Van Nguyen 18.03.2015 / 17:24

3 respostas

3

Você pode fazer isso com a opção grep -B ( --before-context ):

grep -B 20 error filename
    
por 18.03.2015 / 18:17
0

awk: Estou apenas mantendo 5 linhas para esta demonstração, ajuste o valor "keep" para 20

{ seq 10; echo ERROR; seq 6; } |
awk -v keep=5 '
  /ERROR/ {
    for (i=keep; i>=1; i--) print lines[i]  # the stored lines
    print                                   # the current line
    while (getline > 0) print               # all the remaining lines
  }
  {
    # remember the previous "keep" lines.
    for (i=keep; i>1; i--)
      lines[i] = lines[i-1]
    lines[1] = $0
  }
'
6
7
8
9
10
ERROR
1
2
3
4
5
6

Outra abordagem: leva 2 leituras pelo arquivo, mas é mais claro, eu acho.

keep=20
lineno=$(sed -n '/ERROR/{=;q;}' file)
[[ -n $lineno ]] && sed -n "$((lineno-keep)),\$p" file
    
por 18.03.2015 / 20:02
0

Se eu estivesse fazendo isso no bash, faria algo assim:

line=$(grep -m1 -n ERROR the_file | cut -f1 -d:)
if ((line <= 20)); then
  cat the_file;
else
  tail -n+$((line-20)) the_file
fi

que usa grep com a opção "mostrar números de linha" · para obter o número da linha da partida e tail -n para imprimir a partida com a 20ª linha anterior, evitando um número de linha inicial negativo .

Em qualquer outro idioma, a solução seria manter um buffer contínuo (talvez circular) das últimas 20 linhas lidas. Por exemplo, no awk, com um buffer circular:

awk -v P=20 'found  { print; next }
             /ERROR/{ for (i=NR+1;i<=NR+P;++i) 
                        if (i%P in saved)
                          print saved[i%P]
                      found = 1
                    }
                    { saved[NR%P] = $0 }'
    
por 19.03.2015 / 22:04