Extraer y reorganizar del archivo

Extraer y reorganizar del archivo

Tengo un archivo que quiero extraer y reorganizar ciertos datos. El archivo antiguo contiene datos sin procesar, este archivo es la entrada.

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

y el siguiente archivo es el nuevo archivo que contiene el resultado requerido

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

Explicación: por ejemplo, sid:45917, hay cuatro referencias (referencia:cve,2016-10033 referencia:cve,2016-10034 referencia:cve,2016-10045 referencia:cve,2016-10074), necesitamos dividir cada referencia y agregue sid uno debajo del otro (nota: sid siempre va seguido de referencia), de esta manera hay bloques repetitivos, por lo que si hay varias referencias debemos agregarlas en el orden Nuevo archivo.

Respuesta1

Como pareces usarpospuesto sid:s (multipe references:seguido de sus sids:pares únicos => de references:y sid:), dos soluciones.


Solución 1: invertir

Simplemente use el taccomando (esgatoen orden inverso) para invertir la entrada y la salida:tac input | awk | tac > output

Por parte extraña, simplemente duplique el sid:s:

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

Solución 2: matriz

Guarde los reference:s en una matriz tal como vienen y luego escúpelos cuando encuentre los correspondientes.sid:

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 línea que comienza con ref... almacene la línea en una matriz y mueva el puntero 'r' al siguiente elemento.

/^sid:/{for(n=0;n<r;n++){print ref[n] "\n" $0};r=0}: siempre que una línea comience con sid, recorra toda la matriz hasta el puntero r (para...) y para cada elemento, imprima la referencia almacenada y la línea actual (=sid), luego reinicie la r al principio para comenzar nuevamente con las siguientes referencias.

Respuesta2

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

Explicación:

  • BEGIN { i=0; }Inicialice la variable para asegurarse de que se interprete como un valor numérico 0, no como una cadena vacía "".
  • /^reference:/ { ref[i++] = $0; }Para cada línea que comienza con reference:( ^es un ancla al comienzo de la línea), copie la línea completa $0en un elemento de matriz ref[i]e incremente el índice.i++
  • /^sid:/ { ... }por cada línea que comienza con sid:...
  • for(j=0; j<i; j++) { ... }Como iapunta al elemento de la matriz después del último utilizado, recorra todos los elementos de la matriz en los que se han escrito usando index j.
  • print ref[j];imprimir el contenido del elemento de la matriz, es decir, una reference:línea guardada
  • print;imprimir la línea actual, es decir, la sid:línea
  • i=0;restablecer el índice de la matriz al principio para el siguiente grupo de reference:líneas

El guión se basa en los siguientes supuestos:

  • La entrada consta de una serie de bloques donde cada bloque contiene
    • una secuencia de una o más reference:líneas seguidas de
    • una sola sid:linea
  • La última línea debe ser una sid:línea.
  • Se ignorarán las líneas que no coincidan.

Con la pregunta original asumí la dirección incorrecta de la conversión. El segundo script convierte en la dirección opuesta:

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

Explicación:

  • BEGIN { oldsid=""; ref=""; }Inicialice las variables para mayor claridad, no es realmente necesario.
  • /^reference:/ { ref=$0; }Para cada línea que comienza con reference:guarde la línea $0en variable ref, no la imprima todavía.
  • /^sid:/ { ... }Por cada línea que comienza con sid:...
  • if(oldsid != $0) { if(oldsid != "") print oldsid; }Si la sid:línea ha cambiado ahora, la última reference:línea guardada refpertenece a la nueva sid:, por lo que no la imprimimos todavía. Si oldsidno está vacío, podemos imprimirlo ahora que el bloque anterior de reference:líneas con el mismo sid:ha terminado. oldsidEstará vacío cuando encontremos el primero sid:.
  • if(ref!="")print ref;Si tenemos uno guardado reference:, imprímelo ahora. (O acabamos de cerrar el bloque anterior con la sid:línea correspondiente o ahora sabemos que el actual reference:tiene el mismo sid:que el anterior). La verificación de una cadena vacía no es realmente necesaria ya que supongo que cada sid:línea está precedida por una reference:línea.
  • oldsid=$0;guarde la sid:línea actual para la comparación cuando obtengamos la siguiente. La línea actual aún no se ha impreso.
  • END { if (oldsid != "") print oldsid; }Al final, imprima la última sid:línea guardada, si la hay. (Si el archivo de entrada está vacío, no imprimirá una línea vacía aquí).

Este script se basa en estas suposiciones:

  • cada reference:es seguido por unsid:
  • todos los pares de reference:y sid:con la misma sid:recta se suceden

información relacionada