Użycie awk do zsumowania wartości kolumny na podstawie wartości innej kolumny

63

Próbuję zsumować określone liczby w kolumnie za pomocą awk. Chciałbym zsumować tylko kolumnę 3 „kowala”, aby uzyskać w sumie 212. Całą kolumnę mogę zsumować, awkale nie tylko „kowali”. Mam:

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

Używam również szpachli. Dziękuję za wszelką pomoc.

smiths|Login|2
olivert|Login|10
denniss|Payroll|100
smiths|Time|200
smiths|Logout|10
jake
źródło

Odpowiedzi:

81
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • -FFlaga przedstawia separator dziedzinie; Umieszczam go w cudzysłowie, ponieważ jest to specjalny znak powłoki.
  • Następnie $1 ~ /smiths/stosuje następujący {blok kodu} tylko do wierszy, w których pierwsze pole odpowiada wyrażeniu regularnemu /smiths/.
  • Reszta jest taka sama jak kod.

Zauważ, że ponieważ tak naprawdę nie używasz wyrażenia regularnego tutaj, tylko konkretna wartość, możesz równie łatwo użyć:

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

Który sprawdza równość ciągów. Jest to równoważne z użyciem wyrażenia regularnego /^smiths$/, jak wspomniano w innej odpowiedzi, która obejmuje ^kotwicę dopasowującą tylko początek łańcucha (początek pola 1) i $kotwicę, która pasuje tylko do końca łańcucha. Nie jestem pewien, czy znasz się na wyrażeniach regularnych. Są bardzo potężne, ale w tym przypadku można równie łatwo zastosować kontrolę równości łańcucha.

Dzika karta
źródło
3
Nawiasem mówiąc, mój ulubiony odnośnik do awk to grymoire.com/Unix/Awk.html . Bardzo pomocna strona.
Wildcard
1
Dziękuję @Wildcard! Udało mi się starannie zebrać nieskompresowany rozmiar poszczególnych plików w dużym archiwum zip na podstawie Twojej porady :) unzip -lv /appl/tmp/data.lar | grep documentlibrary | awk '{sum += $1} END {print sum/1024/1024}'
Pawel
15

Innym podejściem jest użycie tablic asocjacyjnych awk, więcej informacji tutaj . Ten wiersz daje pożądany wynik:

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

Jako efekt uboczny tablica przechowuje wszystkie pozostałe wartości:

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

Wynik:

smiths 212
denniss 100
olivert 10
Andrey
źródło
To właściwa odpowiedź
PoVa
5

Jak dotąd bardzo dobrze. Wszystko, co musisz zrobić, to dodać selektor przed blokiem, aby dodać sumę. Tutaj sprawdzamy, czy pierwszy argument zawiera tylko „kowale”:

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

Możesz to trochę skrócić, określając jako separator pola. W awkto generalnie dobry pomysł, aby zainicjować zmiennych w wierszu poleceń:

awk -F'|' '$1 ~ /^smiths$/ {sum+=$3} END {print sum}'
RobertL
źródło
0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F opcja określenia separatora.
  • $NF dotyczy „ostatniej kolumny”.
forzagreen
źródło
1
cati grepsą tutaj niepotrzebne.
Andrey
Dlaczego grep nie jest potrzebny @Andrey? OP chce dodawać tylko wiersze „kowale”. Musisz zmodyfikować instrukcję awk, prawda?
EL
1
@EL tak, należy zmienić instrukcję awk, /smiths/{...}jeśli nie ma wywołania grep. Jest to trywialna modyfikacja, ale zapewnia znaczące korzyści: zmniejsza liczbę uruchomionych procesów, upraszcza kontrolę błędów i czyni kod wyraźniejszym.
Andrey
0

Osobiście wolałbym, aby awksekcja była tak prosta, jak to możliwe, i robiłaby jak najwięcej bez niej. Połączona logika nie wykorzystuje mocy potoków uniksowych i dlatego jest trudniejsza do zrozumienia, debugowania lub modyfikacji w ściśle powiązanych przypadkach użycia.

cat filename.txt | perl -pe 's{.*|}{}g' | awk '{sum+=$1} END {print sum}'
Sridhar Sarnobat
źródło