¿Es posible fusionar filas en función de los valores únicos compuestos de dos columnas?

¿Es posible fusionar filas en función de los valores únicos compuestos de dos columnas?

Lo siento, soy muy nuevo en Linux y no estoy seguro de la capacidad de bash para lo que quiero lograr.

Quiero fusionar los valores de la columna 2 si los valores de la columna 1 y la columna 3 son idénticos. En este caso, si hay las mismas descripciones de error y el mismo comerciante, quiero fusionar los campos RefNo por coma.

Error Desc|RefNo|Merchant
===================================
Category code invalid|03077|merchanta
Category code invalid|09877|merchanta
Invalid ID|12345|merchanta
Invalid ID|07323|merchantc
Invalid ID|03523|merchantc
No valid reason|78653|merchantb

Gastos esperados:

Error Desc|RefNo|Merchant
===================================
Category code invalid|03077,09877|merchanta
Invalid ID|12345|merchanta
Invalid ID|07323,03523|merchantc
No valid reason|78653|merchantb

Encontré publicaciones similares, pero están eliminando duplicados y no quiero eliminar ni fusionar la columna 2. Mantener filas únicas basadas en información de 2 de tres columnas.

Respuesta1

Con GNU datamashpodrías hacer:

datamash -t'|' groupby 1,3 collapse 2 < <(tail -n+3 file)

Producción:

Category code invalid|merchanta|03077,09877
Invalid ID|merchanta|12345
Invalid ID|merchantc|07323,03523
No valid reason|merchnatb|78653

Esto agrupa el primer y tercer campo y colapsa los valores del segundo campo. Se tail -n+3utiliza para omitir las dos líneas de encabezado.

Podrías usar awkpara intercambiar la segunda y tercera columna del resultado y headagregar las líneas de encabezado:

{
  head -n2 file
  datamash -t'|' groupby 1,3 collapse 2 < <(tail -n+3 file) | 
    awk 'BEGIN{OFS=FS="|"}{print $1,$3,$2}'
}

Producción:

Error Desc|RefNo|Merchant
===================================
Category code invalid|03077,09877|merchanta
Invalid ID|12345|merchanta
Invalid ID|07323,03523|merchantc
No valid reason|78653|merchnatb

Respuesta2

Probablemente estoy pasando por alto algo (probablemente sea posible acortarlo), pero esto funciona:

awk '
    BEGIN   {   FS="|"; OFS="|" }
    NR <= 2
    NR > 2  {
                seen_desc[$1]++
                seen_merc[$3]++
                if (ref[$1,$3] == "")
                        ref[$1,$3] = $2
                else
                        ref[$1,$3] = ref[$1,$3] "," $2
            }
    END     {
                for (desc in seen_desc) {
                        for (merc in seen_merc) {
                                if (ref[desc,merc] != "") {
                                        print desc, ref[desc,merc], merc
                                }
                        }
                }
            }'

información relacionada