Extrai linhas de um arquivo de texto baseado em um parâmetro para uma única linha

1

Sou bastante novo em scripts, por isso agradeço qualquer ajuda. Eu tenho um arquivo de texto que, em alguns casos, pode ser bastante longo, cada seção de linhas de texto pode ser em torno de 6/7 linhas de comprimento. É um arquivo de log e cada seção começa com a palavra timestamp. Há uma linha em branco entre cada seção de linhas. Cada linha de seção termina com um ponto e vírgula.

timestamp=201706291035.....;
  line 2;
  line 3;
  line 4;
  line 5;
  line 6;
  line 7;

timestamp=201706291038.....;
  line 2;
  line 3;
  line 4;
  line 5;
  line 6;

Eu preciso extrair cada seção para outro arquivo de texto em uma única linha. De preferência sem o último ponto-e-vírgula.

timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6

Isso é informação suficiente para uma solução?

Aqui está um exemplo direto:

timestamp = 2017-06-28-01.01.35.080576;
  status do evento = 0 e
  userid = user1;
  authid = user1;
  id de aplicativo = 10.10.10.10.11111.12345678901;
  nome do aplicativo = GUI;

timestamp = 2017-06-28-01.01.36.096486;
  status do evento = 0 e
  userid = user1;
  authid = user1;
  id de aplicativo = 10.10.10.10.11111.12345678901;
  nome do aplicativo = GUI;
  texto da instrução = SELECT table.field, table.field, table.field do banco de dados em que table.field = value

Depois de executar os scripts @steeldriver, os arquivos de origem e de destino parecem iguais.

    
por david 29.06.2017 / 21:21

5 respostas

4

Isso pode ser feito com o awk idiomático assim:

awk '$1=$1' RS= OFS= infile

Saída:

timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7;
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6;

Explicação

Há muita coisa embalada aqui. Basicamente, existem três etapas:

  1. Primeiro, a entrada é dividida em registros com base no separador de registro ( RS ).
  2. Cada registro é dividido em campos com base no separador de campos ( FS ).
  3. Ao imprimir, o separador do campo de saída ( OFS ) é usado como o delimitador de campo.

Quando o awk analisa sua entrada, existem várias regras implícitas no trabalho. Os dados são lidos, um registro por vez, sendo os registros separados por RS (o padrão é \n ). Quando RS está vazio, como no exemplo acima, uma linha vazia delimita registros. Assim, cada seção é lida como um registro.

Para forçar awk a substituir FS por OFS , definimos o primeiro campo $1 para si mesmo.

Editar

Como observado por steeldriver , o OP quer remover o ponto-e-vírgula à direita. Sem vergonha copiada:

awk '{ sub(/;$/,"",$NF); $1=$1 } 1' RS= OFS= infile
    
por 29.06.2017 / 21:49
1

Isso pode ser feito da seguinte maneira:

perl -lF';\n?' -00ne '$,=";"; print @F' yourfile

Saída

timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6

Trabalhando

  1. Opções Perl

    a) -l = > ORS="\ n" + RS="\ n"

    b) -F';\n?' = > fará com que o FS seja um ponto e vírgula seguido por uma nova linha opcional.

    c) -00 = > fará RS =, permitindo assim o modo de parágrafo.

    d) -n = > permitirá a leitura implícita do arquivo + impressão explícita.

  2. Principal: $,=; fará do OFS um ponto-e-vírgula, @F são os campos que foram gravados no registro atual $_ com base no FS .

por 30.06.2017 / 08:47
0

Se houver uma linha vazia antes do registro de data e hora, você pode usar um simples

perl -pe 'chomp unless /^$/'

Se as novas linhas não estiverem lá, você precisa se lembrar da linha anterior.

perl -pe 'chomp; print "\n" if $. > 1 && /^timestamp=/; print }{ print "\n"'
    
por 29.06.2017 / 21:50
0

A resposta mais curta para o caso de uso seria:

awk '$1=$1' > "single.txt" RS= test.txt

Como RS foi explicado por Thor, só precisamos de RS para obter nosso resultado.

    
por 29.06.2017 / 23:04
0

Só porque, aqui está uma maneira de fazer isso em sed

Tome como ponto de partida este one-liner de Peter Krumins 'Sed One- Folhetos explicados, Parte I: Espaçamento de Arquivos, Numeração e Conversão de Texto e Substituição

  1. Append a line to the next if it ends with a backslash "\".

    sed -e :a -e '/\$/N; s/\\n//; ta'
    

The first expression ':a' creates a named label "a". The second expression looks to see if the current line ends with a backslash "\". If it does, it joins it with the line following it using the "N" command. Then the slash and the newline between joined lines get erased with "s/\n//" command. If the substitution was successful we branch to the beginning of expression and do the same again, in hope that we might have another backslash. If the substitution was not successful, the line did not end with a backslash and we print it out.

substituindo \ por ; e ajustando a substituição para deixar o ; , mas remover os espaços iniciais, obtemos

$ sed -e :a -e '/;$/N; s/\n *//; ta' infile
timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7;

timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6;

Fechar! agora queremos extrair a linha em branco - podemos fazer isso testando se o padrão termina em uma nova linha (ou seja, a linha anexada está vazia) e, se assim for, imprimindo até a nova linha e, em seguida, descartando o padrão:

$ sed -e :a -e '/;$/N; /\n$/{P;d;}; s/\n *//; ta' infile
timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7;
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6;

Agora só precisamos cortar o ; . Uma maneira de fazer isso é remover cada ; à medida que anexamos a linha ao espaço padrão e, em seguida, a reinserimos quando descartamos a nova linha:

$ sed -e :a -e '/;$/{s///;N;}; /\n$/{P;d;}; s/\n */;/; ta' infile
timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6

O ; final não é reinserido porque já comemos a nova linha com {P;d;} , por isso a substituição s//\n /;/ não é aplicada.

    
por 30.06.2017 / 20:21

Tags