Utiliser awk pour additionner les valeurs d'une colonne, en fonction des valeurs d'une autre colonne

64

J'essaie de faire la somme de certains nombres dans une colonne en utilisant awk. Je voudrais résumer seulement la colonne 3 des "forgerons" pour obtenir un total de 212. Je peux résumer la colonne entière en utilisant awkmais pas seulement les "forgerons". J'ai:

awk 'BEGIN {FS = "|"} ; {sum+=$3} END {print sum}' filename.txt

J'utilise aussi du mastic. Merci pour toute aide.

smiths|Login|2
olivert|Login|10
denniss|Payroll|100
smiths|Time|200
smiths|Logout|10
Jake
la source

Réponses:

82
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • Le -Fdrapeau définit le séparateur de champ; Je le mets entre guillemets car il s’agit d’un caractère de shell spécial.
  • $1 ~ /smiths/Applique ensuite le {bloc de code} suivant uniquement aux lignes où le premier champ correspond à la regex /smiths/.
  • Le reste est identique à votre code.

Notez que puisque vous n'utilisez pas vraiment une expression régulière ici, mais juste une valeur spécifique, vous pouvez tout aussi facilement utiliser:

awk -F '|' '$1 == "smiths" {sum += $3} END {print sum}' inputfilename

Qui vérifie l'égalité des chaînes. Ceci équivaut à utiliser l'expression régulière /^smiths$/, comme mentionné dans une autre réponse, qui inclut l' ^ancre pour correspondre uniquement au début de la chaîne (le début du champ 1) et l' $ancre pour ne faire correspondre que la fin de la chaîne. Vous ne savez pas à quel point vous êtes familier avec les regex. Ils sont très puissants, mais dans ce cas, vous pouvez utiliser un contrôle d’égalité de chaîne tout aussi facilement.

Wildcard
la source
3
En passant, ma référence favorite pour awk est grymoire.com/Unix/Awk.html . Page très utile.
Wildcard
1
Merci @Wildcard! J'ai été en mesure d'agréger proprement une taille non compressée de fichiers particuliers dans une grande archive zip, en fonction de vos conseils. unzip -lv /appl/tmp/data.lar | grep documentlibrary | awk '{sum += $1} END {print sum/1024/1024}'
Pawel 12/12
15

Une autre approche consiste à utiliser des tableaux associatifs awk, plus d’informations ici . Cette ligne produit la sortie souhaitée:

awk -F '|' '{a[$1] += $3} END{print a["smiths"]}' filename.txt

Comme effet secondaire, le tableau stocke toutes les autres valeurs:

awk -F '|' '{a[$1] += $3} END{for (i in a) print i, a[i]}' filename.txt

Sortie:

smiths 212
denniss 100
olivert 10
Andrey
la source
C'est la bonne réponse
PoVa
5

Très bien jusqu'à présent. Tout ce que vous avez à faire est d’ajouter un sélecteur avant le bloc pour ajouter la somme. Nous vérifions ici que le premier argument ne contient que "forgerons":

awk 'BEGIN {FS = "|"} ; $1 ~ /^smiths$/ {sum+=$3} END {print sum}'

Vous pouvez abréger un peu en spécifiant le séparateur de champs en option. C'est awkgénéralement une bonne idée d'initialiser des variables sur la ligne de commande:

awk -F'|' '$1 ~ /^smiths$/ {sum+=$3} END {print sum}'
RobertL
la source
0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F option pour spécifier le séparateur.
  • $NF est pour "dernière colonne".
forzagreen
la source
1
catet grepsont inutiles ici.
Andrey
Pourquoi grep n'est-il pas nécessaire @Andrey? OP veut ajouter uniquement des lignes "forgerons". Vous auriez besoin de modifier la déclaration awk, non?
EL
1
@EL oui, l'instruction awk doit être modifiée /smiths/{...}si l'appel de grep n'y est pas. Il s’agit d’une modification anodine, mais qui offre d’importants avantages: elle réduit le nombre de processus en cours, simplifie le contrôle des erreurs et rend le code plus clair.
Andrey
0

Personnellement, je préférerais que la awksection soit aussi simple que possible et que je fasse tout ce que vous pourrez sans elle. La logique intégrée ne tire pas parti de la puissance des pipelines Unix et est donc plus difficile à comprendre, à déboguer ou à modifier pour des cas d'utilisation étroitement liés.

cat filename.txt | perl -pe 's{.*|}{}g' | awk '{sum+=$1} END {print sum}'
Sridhar Sarnobat
la source