Suma de columnas para filas que contienen un término específico

Me pregunto si hay algún command sed o awk que pueda sumr todas las columnas de las filas con un identificador idéntico. Por ejemplo, mi file data.txt se establece a continuación, excepto que contiene ~ 1800 columnas de datos y ~ 1400 filas.

 ABCD:1234 1.23 0.23 0.83 0 ABCD:1234 0 1.10 0.21 0 EFGH:5678 0 1.90 0.12 8.21 IJKL:9999 1.22 0 1.84 9.21 IJKL:9999 1.44 0 12.94 0 IJKL:9999 1.32 0 24.12 2.43 

Y cómo me gustaría que fuera después de que el command fuera así:

 ABCD:1234 1.23 1.33 1.04 0 EFGH:5678 0 1.90 0.12 8.21 IJKL:9999 3.98 0 38.9 11.64 

No estoy seguro de si esto es posible con awk o sed (soy biólogo y aún estoy aprendiendo los principios básicos de Unix). Cualquier ayuda sería muy apreciada.

Una secuencia de commands awk que no contiene ni el file de input ni toda la tabla de resultados en la memory:

 FNR == 1 { for(i = 1; i <= NF; i++) a[i] = $i; next } $1 == a[1] { for(i = 2; i <= NF; i++) a[i] += $i; next } { printf "%s", a[1]; a[1] = $1; for(i = 2; i <= NF; i++) { printf "\t%s", a[i]; a[i] = $i }; printf "\n"; } END { printf "%s", a[1]; for(i = 2; i <= NF; i++) printf "\t%s", a[i]; printf "\n"; } 

Para ejecutarlo:

 awk -f script.awk data.txt 

Resultados:

 ABCD:1234 1.23 1.33 1.04 0 EFGH:5678 0 1.90 0.12 8.21 IJKL:9999 3.98 0 38.9 11.64 

En una nota al margen: en realidad es posible hacerlo con sed . Sin embargo, no lo harás pronto. Mira aquí para tener una idea de por qué.

Solución alternativa con perl

 $ perl -nale ' if(!$seen{$F[0]}++) { print join "\t", @a if @a; @a = @F[0..$#F]; } else { $a[$_] += $F[$_] foreach(1..$#F); } print join "\t", @a if eof; ' data.txt ABCD:1234 1.23 1.33 1.04 0 EFGH:5678 0 1.90 0.12 8.21 IJKL:9999 3.98 0 38.9 11.64 
  • -a divide la línea de input en los espacios y los guarda en la matriz @F
  • El primer campo de línea se usa como una key para hash variable %seen , si la key no se encuentra, imprime el contenido de una matriz siempre que no esté vacía y asigne la matriz con campos de nueva línea
  • Si la key ya existe, incremente el contenido de la matriz (desde el segundo campo hasta el final) con los contenidos correspondientes de la línea actual
  • Para manejar la última input, imprima el contenido de @a array nuevamente cuando se llega al final del file

Para la pregunta duplicada: agregue todas las columnas por separado en Linux si la primera columna tiene las mismas inputs

 $ perl -nale ' if(!$seen{$F[0]}++) { print join "\t", @a if @a; @a = @F[0..$#F]; } else { $a[$_] += $F[$_] foreach(1..$#F); } print join "\t", @a if eof; ' filename.txt AC1481523 6 6 6 6 AC1481676 6 5 6 8 

Solución con crear un hash de matrices e imprimir el hash al final:

 $ perl -nale ' if($h{$F[0]}) { $h{$F[0]}[$_] += $F[$_] foreach (1..$#F) } else { $h{$F[0]} = [@F] } END { print join "\t",@{$h{$_}} foreach sort keys %h } ' data.txt ABCD:1234 1.23 1.33 1.04 0 EFGH:5678 0 1.90 0.12 8.21 IJKL:9999 3.98 0 38.9 11.64