Extrair e reorganizar do arquivo

Extrair e reorganizar do arquivo

Eu tenho um arquivo que desejo extrair e reorganizar determinados dados. O arquivo antigo contém dados brutos, este arquivo é de entrada

referência:cve,2017-8962
sid:45885
referência:cve,2016-10033
referência:cve,2016-10034
referência:cve,2016-10045
referência:cve,2016-10074
sid:45917
referência:cve,2017-8046
sid:45976
referência:cve,2018-6577
referência:cve,2018-6578
sid:46062

e o arquivo abaixo é o novo arquivo que contém a saída necessária

referência:cve,2017-8962
sid:45885
referência:cve,2016-10033
sid:45917
referência:cve,2016-10034
sid:45917
referência:cve,2016-10045
sid:45917
referência:cve,2016-10074
sid:45917
referência:cve,2017-8046
sid:45976
referência:cve,2018-6577
sid:46062
referência:cve,2018-6578
sid:46062
.

Explicação: para exemplo sid:45917 existem quatro referências (referência:cve,2016-10033 referência:cve,2016-10034 referência:cve,2016-10045 referência:cve,2016-10074), precisamos dividir cada referência e anexe o lado um abaixo do outro (nota: sid é sempre seguido por referência), assim existem blocos repetitivos, portanto, se houver múltiplas referências, precisaremos anexá-las em Nova ordem de arquivo.

Responder1

Como você parece usaradiado sid:s (múltiplo references:seguido por seus sids:pares únicos => de references:e sid:), duas soluções.


Solução 1: reversão

Simples use otac comando (égatona ordem inversa) para inverter a entrada e a saída:tac input | awk | tac > output

Para a parte awk, basta duplicar o sid:s:

gawk '/^sid:/{sid=$0};/^reference:/{print sid "\n" $0}'

Solução 2: matriz

Armazene os reference:s em uma matriz à medida que eles surgirem e, em seguida, cuspa-os de volta ao encontrar os correspondentessid:

gawk 'BEGIN{r=0};/^reference:/{ref[r++]=$0};/^sid:/{for(n=0;n<r;n++){print ref[n] "\n" $0};r=0}' /tmp/test.txt

/^reference:/{ref[r++]=$0}: para cada linha que começa com ref... armazene a linha em um array e mova o ponteiro 'r' para o próximo elemento.

/^sid:/{for(n=0;n<r;n++){print ref[n] "\n" $0};r=0}: sempre que uma linha começar com sid, percorra todo o array até o ponteiro r (para...) e para cada elemento, imprima a ref armazenada e a linha atual (=sid), depois redefina o r de volta ao início para começarmos novamente com as próximas referências.

Responder2

awk 'BEGIN { i=0; }
/^reference:/ { ref[i++] = $0; }
/^sid:/ { for(j=0; j<i; j++) { print ref[j]; print; } i=0; }' inputfile > outputfile

Explicação:

  • BEGIN { i=0; }Inicialize a variável para garantir que ela seja interpretada como um valor numérico 0e não como uma string vazia "".
  • /^reference:/ { ref[i++] = $0; }Para cada linha que começa com reference:( ^é uma âncora para o início da linha), copie a linha inteira $0para um elemento do array ref[i]e aumente o índicei++
  • /^sid:/ { ... }para cada linha que começa com sid:...
  • for(j=0; j<i; j++) { ... }Como iaponta para o elemento da matriz após o último usado, faça um loop sobre todos os elementos da matriz que foram gravados usando index j,
  • print ref[j];imprime o conteúdo do elemento do array, ou seja, uma reference:linha salva
  • print;imprima a linha atual, ou seja, a sid:linha
  • i=0;redefinir o índice da matriz para o início para o próximo grupo de reference:linhas

O script é baseado nas seguintes suposições:

  • A entrada consiste em uma série de blocos onde cada bloco contém
    • uma sequência de uma ou mais reference:linhas seguida por
    • uma única sid:linha
  • A última linha deve ser uma sid:linha.
  • Linhas não correspondentes serão ignoradas.

Com a pergunta original, presumi a direção errada da conversão. O segundo script converte na direção oposta:

awk 'BEGIN { oldsid=""; ref=""; }
/^reference:/ { ref=$0; }
/^sid:/ { if(oldsid != $0) { if(oldsid != "") print oldsid; } if(ref!="")print ref; oldsid=$0; }
END { if (oldsid != "") print oldsid; }' inputfile > outputfile

Explicação:

  • BEGIN { oldsid=""; ref=""; }Inicializar variáveis ​​para maior clareza, não é realmente necessário.
  • /^reference:/ { ref=$0; }Para cada linha que começa com reference:save the line $0to variable ref, não imprima ainda.
  • /^sid:/ { ... }Para cada linha que começa com sid:...
  • if(oldsid != $0) { if(oldsid != "") print oldsid; }Se a sid:linha mudou agora, a última reference:linha salva refpertence ao new sid:, então não a imprimimos ainda. Se oldsidnão estiver vazio podemos imprimi-lo agora que o bloco de reference:linhas anterior com o mesmo sid:foi concluído. oldsidestará vazio quando encontrarmos o primeiro sid:.
  • if(ref!="")print ref;Se tivermos um arquivo salvo reference:, imprima-o agora. (Ou acabamos de fechar o bloco anterior com a sid:linha correspondente ou sabemos agora que a corrente reference:é igual sid:à anterior.) A verificação de string vazia não é realmente necessária, pois presumo que cada sid:linha seja precedida por uma reference:linha.
  • oldsid=$0;salve a sid:linha atual para comparação quando chegarmos à próxima. A linha atual ainda não foi impressa.
  • END { if (oldsid != "") print oldsid; }No final imprima a última sid:linha salva, se houver. (Se o arquivo de entrada estiver vazio, não imprimirá uma linha vazia aqui.)

Este script é baseado nestas suposições:

  • cada reference:é seguido por umsid:
  • todos os pares de reference:e sid:com a mesma sid:linha seguem um ao outro

informação relacionada