
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érico0
e não como uma string vazia""
./^reference:/ { ref[i++] = $0; }
Para cada linha que começa comreference:
(^
é uma âncora para o início da linha), copie a linha inteira$0
para um elemento do arrayref[i]
e aumente o índicei++
/^sid:/ { ... }
para cada linha que começa comsid:
...for(j=0; j<i; j++) { ... }
Comoi
aponta para o elemento da matriz após o último usado, faça um loop sobre todos os elementos da matriz que foram gravados usando indexj
,print ref[j];
imprime o conteúdo do elemento do array, ou seja, umareference:
linha salvaprint;
imprima a linha atual, ou seja, asid:
linhai=0;
redefinir o índice da matriz para o início para o próximo grupo dereference:
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
- uma sequência de uma ou mais
- 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 comreference:
save the line$0
to variableref
, não imprima ainda./^sid:/ { ... }
Para cada linha que começa comsid:
...if(oldsid != $0) { if(oldsid != "") print oldsid; }
Se asid:
linha mudou agora, a últimareference:
linha salvaref
pertence ao newsid:
, então não a imprimimos ainda. Seoldsid
não estiver vazio podemos imprimi-lo agora que o bloco dereference:
linhas anterior com o mesmosid:
foi concluído.oldsid
estará vazio quando encontrarmos o primeirosid:
.if(ref!="")print ref;
Se tivermos um arquivo salvoreference:
, imprima-o agora. (Ou acabamos de fechar o bloco anterior com asid:
linha correspondente ou sabemos agora que a correntereference:
é igualsid:
à anterior.) A verificação de string vazia não é realmente necessária, pois presumo que cadasid:
linha seja precedida por umareference:
linha.oldsid=$0;
salve asid:
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 últimasid:
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:
esid:
com a mesmasid:
linha seguem um ao outro