Leia o arquivo, encontre todas as ocorrências e gere hash para o conteúdo entre as ocorrências

1

Eu tenho um arquivo como este:

1   Record|1111|ABC
2   text in between for record 1
3   text in between for record 1
4   Record|2222|XYZ
5   text in between for record 2    
6   Record|3333|XYZ
7   text in between for record 3
8   .

Eu quero ler este arquivo e gerar algo como

<Record_number> | <start line> | <number of lines> | md5sum(content)

Isto é:

1111|1|2|md5sum(Record|1111|ABC\ntext in between for record 1\ntext in between for record 1)
2222|4|1|md5sum(Record|2222|XYZ\ntext in between for record 2\n)

etc.

Atualmente, estou fazendo isso usando um processo de duas etapas:

Etapa 1:

grep -n -C 0 "Record|" ../test.txt | awk -F[':|'] '{print $3"|"$1}'

criará

1111|1
2222|4
3333|6

Etapa 2: Leia este arquivo linha por linha e gere o md5sum e o número de linhas através do script.

O problema é que esse processamento em duas etapas está levando mais tempo de processamento e o tamanho do arquivo é enorme (~ 4 GB).

Existe uma maneira melhor de fazer isso?

    
por Sinoop Joy 21.11.2014 / 09:54

2 respostas

0

Baseado na resposta de Costas.

1) Crie um arquivo parse.awk, com o seguinte conteúdo:

/^Record/ {
  if (s>0) {
    printf ("%s|%s|", r,l)
    system("echo '"line"' | md5sum - | awk '{print $1}' ");
  }
  s=1;
  r=$2;
  c=1;
  l=NR;
  line="$0";
}
!/^Record/ {
  line=line"\n""$0";
  c+=1
}
END {
  printf ("%s|%s|", r,l)
  system("echo '"line"' | md5sum - | awk '{print $1}' ");
}

Veja as explicações de Costas. Este script apenas faz printf o início da linha resultante (em vez de imprimir, que coloca uma nova linha) system(echo $line | md5sum) para imprimir o md5 - e uma nova linha

2) Executar awk -F"|" -f parse.awk myfile

3) Aproveite o resultado:

1111|1|cb36533781d8dd00011a85b0db9b87b3
2222|4|521331bb249e8a668afa2199fa8d289a
3333|6|6c2564464187094e9db3159d26ade2a5
    
por 21.11.2014 / 14:14
1

Principalmente pode ser

awk -F"|" -v OFS="|" '
function md5(lines){
  func="printf \"%s\" \""lines"\"|md5sum|cut -f1 -d\ " ;
  func | getline v;
  return v
}
/Record/{
  if(s>0)
    print r,l,c,md5(line);
  s=1;
  r=$2;
  c=1;
  l=NR;
  line=$0
}
!/Record/{
  line=line"\n"$0;
  c+=1
}
END{
  print r,l,c,md5(line);
}' file

Explicação resumida do código:

  1. Altere os separadores de campo (entrada e saída) para |

  2. Atribuir md5 função (graças a Pierre-Olivier Vares por ideia ) para calcular md5sum para linhas de entrada apropriadas. (pode haver melhor maneira de fazer isso - você está convidado a comentar)

  3. Para linhas que têm Record palavra coloque os campos necessários em variáveis e quebre os contadores para 1 e imprima a linha formatada anterior a partir da segunda ocorrência de Record word (para as segundas impressões primeiro, para as segundas impressões em).

  4. Para linhas que não têm Record word, basta adicionar-se à variável line e adicionar 1 ao contador c

  5. Quando o acabamento imprimir a última linha formatada (porque a última linha é armazenada na memória e deve ser impressa quando atender à próxima Record palavra, mas tiver atendido o fim do arquivo)

por 21.11.2014 / 12:34