
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 tac
comando (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érico0
, no como una cadena vacía""
./^reference:/ { ref[i++] = $0; }
Para cada línea que comienza conreference:
(^
es un ancla al comienzo de la línea), copie la línea completa$0
en un elemento de matrizref[i]
e incremente el índice.i++
/^sid:/ { ... }
por cada línea que comienza consid:
...for(j=0; j<i; j++) { ... }
Comoi
apunta al elemento de la matriz después del último utilizado, recorra todos los elementos de la matriz en los que se han escrito usando indexj
.print ref[j];
imprimir el contenido del elemento de la matriz, es decir, unareference:
línea guardadaprint;
imprimir la línea actual, es decir, lasid:
líneai=0;
restablecer el índice de la matriz al principio para el siguiente grupo dereference:
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
- una secuencia de una o más
- 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 conreference:
guarde la línea$0
en variableref
, no la imprima todavía./^sid:/ { ... }
Por cada línea que comienza consid:
...if(oldsid != $0) { if(oldsid != "") print oldsid; }
Si lasid:
línea ha cambiado ahora, la últimareference:
línea guardadaref
pertenece a la nuevasid:
, por lo que no la imprimimos todavía. Sioldsid
no está vacío, podemos imprimirlo ahora que el bloque anterior dereference:
líneas con el mismosid:
ha terminado.oldsid
Estará vacío cuando encontremos el primerosid:
.if(ref!="")print ref;
Si tenemos uno guardadoreference:
, imprímelo ahora. (O acabamos de cerrar el bloque anterior con lasid:
línea correspondiente o ahora sabemos que el actualreference:
tiene el mismosid:
que el anterior). La verificación de una cadena vacía no es realmente necesaria ya que supongo que cadasid:
línea está precedida por unareference:
línea.oldsid=$0;
guarde lasid:
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 últimasid:
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:
ysid:
con la mismasid:
recta se suceden