unix shell-script – Organizar secciones de bloques de código según fechas y meses

Pregunta:

Tengo un archivo con contenido repetido como este;

<item>
    <date>August 24, 2021</date>
    <p>Text</p>
</item>

<item>
    <date>February 11, 2020</date>
    <p>more text</p>
</item>

<item>
    <date>July 20, 2021</date>
    <p>some text</p>
</item>

Quería obtener algo en el que todas las secciones del elemento se organizarán por fecha, donde el primer elemento de la sección es la última fecha y el último elemento de la sección es la fecha más antigua, algo como esto;

<item>
    <date>August 24, 2021</date>
    <p>Text</p>
</item>

<item>
    <date>July 20, 2021</date>
    <p>some text</p>
</item>

<item>
    <date>February 11, 2020</date>
    <p>more text</p>
</item>

¿Existe alguna posibilidad de hacerlo con sed o awk?

Respuesta:

Con suerte, alguien lo ayudará con una respuesta que use una herramienta compatible con XML, pero si no, y asumiendo que su entrada realmente se parece a la muestra que proporcionó, usando GNU awk para sorted_in :

$ cat tst.awk
BEGIN { RS=""; ORS="\n\n"; FS="</?date>" }
{
    split($2,d,/[, ]+/)
    mthAbbr = substr(d[1],1,3)
    mthNr = ( index( "JanFebMarAprMayJunJulAugSepOcNovDec", mthAbbr ) + 2 ) / 3
    date = sprintf("%04d%02d%02d",d[3], mthNr, d[2])
    items[date] = $0
}
END {
    PROCINFO["sorted_in"] = "@ind_num_desc"
    for ( date in items ) {
        print items[date]
    }
}

$ awk -f tst.awk file <item> <date>August 24, 2021</date> <p>Text</p> </item> <item> <date>July 20, 2021</date> <p>some text</p> </item> <item> <date>February 11, 2020</date> <p>more text</p> </item>

o usando cualquier awk más sort and cut:

 $ cat tst.awk BEGIN { RS=""; FS="\n"; OFS="\t" } { split($2,d,/[<>, ]+/) mthAbbr = substr(d[3],1,3) mthNr = ( index( "JanFebMarAprMayJunJulAugSepOcNovDec", mthAbbr ) + 2 ) / 3 date = sprintf("%04d%02d%02d",d[5], mthNr, d[4]) for (i=1; i<=NF; i++) { print date, NR, i, $i } print date, NR, i, "" }

 $ awk -f tst.awk file | sort -k1,1rn -k2,3n | cut -f4- <item> <date>August 24, 2021</date> <p>Text</p> </item> <item> <date>July 20, 2021</date> <p>some text</p> </item> <item> <date>February 11, 2020</date> <p>more text</p> </item>

El segundo será una mejor opción si su archivo de entrada es enorme, ya que no requiere awk para mantener todo el archivo de entrada en la memoria antes de imprimirlo. Funciona decorando las líneas de entrada para agregar la fecha de cada item seguido del número de registro actual ( item ) seguido del número de línea actual dentro de ese item para que la sort pueda ordenar por date pero conservar el orden de entrada original incluso para fechas duplicadas , y luego cut solo elimina las decoraciones que agregó el primer awk para facilitar la clasificación. Así es como se ve el resultado de los primeros 2 pasos para que pueda ver lo que hacen:

 $ awk -f tst.awk file 20210824 1 1 <item> 20210824 1 2 <date>August 24, 2021</date> 20210824 1 3 <p>Text</p> 20210824 1 4 </item> 20210824 1 5 20200211 2 1 <item> 20200211 2 2 <date>February 11, 2020</date> 20200211 2 3 <p>more text</p> 20200211 2 4 </item> 20200211 2 5 20210720 3 1 <item> 20210720 3 2 <date>July 20, 2021</date> 20210720 3 3 <p>some text</p> 20210720 3 4 </item> 20210720 3 5

 $ awk -f tst.awk file | sort -k1,1rn -k2,3n 20210824 1 1 <item> 20210824 1 2 <date>August 24, 2021</date> 20210824 1 3 <p>Text</p> 20210824 1 4 </item> 20210824 1 5 20210720 3 1 <item> 20210720 3 2 <date>July 20, 2021</date> 20210720 3 3 <p>some text</p> 20210720 3 4 </item> 20210720 3 5 20200211 2 1 <item> 20200211 2 2 <date>February 11, 2020</date> 20200211 2 3 <p>more text</p> 20200211 2 4 </item> 20200211 2 5

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top

web tasarım