colonnes de sum basées sur des champs correspondants

J'ai rencontré un problème qui dépasse mes connaissances unix de base et j'apprécierais vraiment de l'aide. J'ai un grand file dans le format suivant:

2 1019 0 12 2 1019 3 0 2 1021 0 2 2 1021 2 0 2 1022 4 5 2 1030 0 1 2 1030 5 0 2 1031 4 4 

Si les valeurs de la colonne deux correspondent, je veux additionner les valeurs des colonnes 3 et 4 des deux lignes, sinon seulement la sum des valeurs de la ligne unique.

Donc, la sortie que j'espère ressemblera à ceci:

 2 1019 15 2 1021 4 2 1022 9 2 1030 6 2 1031 8 

Je suis capable de sortinger les files selon la colonne 2 avec awk ou de sortinger et de sumr les dernières colonnes avec awk, mais seulement pour les lignes individuelles pas pour deux lignes où la colonne 2 correspond.

Je ferais ça en Perl:

 $ perl -lane '$k{"$F[0] $F[1]"}+=$F[2]+$F[3]; END{print "$_ $k{$_}" for keys(%k) }' file 2 1019 15 2 1021 4 2 1030 6 2 1031 8 2 1022 9 

Ou awk:

 awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file 

Si vous voulez que la sortie soit sortingée selon la deuxième colonne, vous pouvez simplement sort pour sort :

 awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file | sort -k2 

Notez que les deux solutions incluent également la 1ère colonne. L'idée est d'utiliser les première et deuxième colonnes comme keys d'un hachage (en perl) ou d'un tableau associatif (en awk). La key de chaque solution est column1 column2 donc si deux lignes ont la même colonne deux mais une colonne différente, elles seront regroupées séparément:

 $ cat file 2 1019 2 3 2 1019 4 1 3 1019 2 2 $ awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file 3 1019 4 2 1019 10 

Peut-être que cela pourrait aider, mais la colonne 1 est-elle toujours 2 et les résultats en dépendent-ils?

 awk '{ map[$2] += $3 + $4; } END { for (i in map) { print "2", i, map[i] | "sort -t't'" } }' file 

ou comme mentionné par glenn jackman dans les commentaires sur le sorting:

 gawk '{ map[$2] += $3 + $4; } END { PROCINFO["sorted_in"] = "@ind_str_asc"; for (i in map) { print 2, i, map[i] } }' file 

Vous pouvez pré-sortinger datatables et laisser awk gérer les détails:

 sort -n infile | awk 'NR>1 && p!=$2 {print p,s} {s+=$3+$4} {p=$2}' 

Sortie:

 1019 15 1021 19 1022 28 1030 34 

Si vous voulez vraiment garder la première colonne, faites quelque chose comme ceci:

 sort -n infile | awk 'NR>1 && p!=$1FS$2 {print p,s} {s+=$3+$4} {p=$1FS$2}' 

Sortie:

 2 1019 15 2 1021 19 2 1022 28 2 1030 34 

Explication

La variable p contient la valeur $2 de la ligne précédente, ou $1FS$2 dans le deuxième cas ci-dessus. Cela signifie que le {print p,s} est déclenché quand $2 de la ligne précédente n'est pas la même que celle de la ligne courante ( p!=$2 ).