Met awk de waarden van een kolom optellen, gebaseerd op de waarden van een andere kolom

Ik probeer bepaalde getallen in een kolom bij elkaar op te tellen met awk. Ik zou alleen kolom 3 van de “smeden” willen optellen om een totaal van 212 te krijgen. Ik kan de hele kolom optellen met awk maar niet alleen de “smeden”. Ik heb:

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

Ook gebruik ik stopverf. Bedankt voor alle hulp.

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

Antwoord

awk -F "|" "$1 ~ /smiths/ {sum += $3} END {print sum}" inputfilename 
  • De vlag -F stelt het veldscheidingsteken in; Ik heb het tussen enkele aanhalingstekens gezet omdat het een speciaal shell-teken is.
  • Vervolgens past $1 ~ /smiths/ het volgende {code block} alleen toe op regels waar het eerste veld overeenkomt met de regex /smiths/.
  • De rest is hetzelfde als uw code.

Merk op dat aangezien u hier niet echt een regex gebruikt, alleen een specifieke waarde, u net zo gemakkelijk gebruik:

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

Welke tekenreeksgelijkheid wordt gecontroleerd. Dit komt overeen met het gebruik van de regex /^smiths$/, zoals vermeld in een andere antwoord, dat het ^ anker bevat om alleen het begin van de tekenreeks (het begin van veld 1) en het $ anker te koppelen aan alleen overeenkomen met het einde van de string. Ik weet niet zeker hoe bekend je bent met regexes. Ze zijn erg krachtig, maar in dit geval zou je net zo gemakkelijk een stringgelijkheidscontrole kunnen gebruiken.

Opmerkingen

  • Trouwens, mijn favoriete awk-referentie is grymoire.com/Unix/Awk.html . Zeer nuttige pagina .
  • Bedankt @Wildcard! Ik was in staat om een ongecomprimeerde grootte van bepaalde bestanden netjes samen te voegen in een groot zip-archief op basis van jouw advies 🙂

Answer

Een andere benadering is om awk associatieve arrays te gebruiken, meer info hier . Deze regel produceert de gewenste uitvoer:

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

Als neveneffect slaat de array alle andere waarden op:

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

Uitvoer:

smiths 212 denniss 100 olivert 10 

Reacties

  • Dit is het juiste antwoord

Antwoord

Tot dusver zeer goed. Het enige dat u hoeft te doen, is een selector vóór het blok toevoegen om de som toe te voegen. Hier controleren we of het eerste argument alleen “smiths” bevat:

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

Je zou dit een beetje kunnen verkorten door het veldscheidingsteken als een optie op te geven. In awk is het over het algemeen een goed idee om variabelen op de opdrachtregel te initialiseren:

awk -F"|" "$1 ~ /^smiths$/ {sum+=$3} END {print sum}" 

Antwoord

Persoonlijk zou ik de awk sectie zo eenvoudig mogelijk willen houden en zo veel mogelijk doen zonder . Comingled logic “profiteert niet van de kracht van Unix-pipelines en is daardoor moeilijker te begrijpen, debuggen of aan te passen voor nauw verwante use-cases.

cat filename.txt | perl -pe "s{.*|}{}g" | awk "{sum+=$1} END {print sum}" 

Answer

cat filename.txt | grep smiths | awk -F "|" "{sum+=$NF} END {print sum}" 
  • -F optie om scheidingsteken op te geven .
  • $NF is voor “laatste kolom”.

Reacties

  • cat en grep zijn hier niet nodig.
  • Waarom is grep niet nodig @Andrey? OP wil alleen " smiths " rijen toevoegen. U ' moet de awk-instructie wijzigen, toch?
  • @EL ja, de awk-instructie moet worden gewijzigd in /smiths/{...} als de grep-oproep er niet is. Dit is een triviale wijziging, maar het biedt aanzienlijke voordelen: het vermindert het aantal actieve processen, vereenvoudigt de foutcontrole en maakt de code duidelijker.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *