Używając awk do sumowania wartości w kolumnie, na podstawie wartości z innej kolumny

Próbuję zsumować określone liczby w kolumnie za pomocą awk. Chciałbym zsumować tylko trzecią kolumnę „kowali”, aby uzyskać łącznie 212. Całą kolumnę mogę zsumować, używając awk, ale nie tylko „kowali”. Mam:

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

Również używam szpachli. Dziękuję za pomoc.

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

Odpowiedź

awk -F "|" "$1 ~ /smiths/ {sum += $3} END {print sum}" inputfilename 
  • Flaga -F ustawia separator pól; Umieszczam go w pojedynczych cudzysłowach, ponieważ jest to specjalny znak powłoki.
  • Następnie $1 ~ /smiths/ stosuje następujący {code block} tylko do wierszy, w których pierwsze pole pasuje do wyrażenia regularnego /smiths/.
  • Reszta jest taka sama jak Twój kod.

Zwróć uwagę, że skoro nie używasz tutaj wyrażenia regularnego, tylko określonej wartości, równie łatwo możesz użyj:

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

Który sprawdza równość ciągów. Jest to równoważne użyciu wyrażenia regularnego /^smiths$/, jak wspomniano w innym odpowiedź, która zawiera kotwicę ^, aby dopasować tylko początek ciągu (początek pola 1) i kotwicę $ tylko do dopasuj koniec ciągu. Nie jestem pewien, jak dobrze znasz wyrażenia regularne. Są one bardzo potężne, ale w tym przypadku równie łatwo możesz użyć sprawdzenia równości w ciągu.

Komentarze

  • Swoją drogą, moim ulubionym odniesieniem do awk jest grymoire.com/Unix/Awk.html . Bardzo pomocna strona .
  • Dziękuję @Wildcard! Zgodnie z twoją radą udało mi się zgrabnie zagregować nieskompresowane rozmiary poszczególnych plików w dużym archiwum zip 🙂

Odpowiedź

Innym podejściem jest użycie tablic asocjacyjnych awk, więcej informacji tutaj . Ta linia daje żądane dane wyjściowe:

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

Jako efekt uboczny, tablica przechowuje wszystkie inne 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 

Komentarze

  • To jest właściwa odpowiedź

Odpowiedź

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

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

Można to nieco skrócić, określając separator pól jako opcję. W awk dobrym pomysłem jest zainicjowanie zmiennych w wierszu poleceń:

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

Odpowiedz

Osobiście wolałbym, aby sekcja awk była tak prosta, jak to tylko możliwe, i robić jak najwięcej bez niej . Logika nie wykorzystuje potoków uniksowych i dlatego jest trudniejsza do zrozumienia, debugowania lub modyfikacji dla ściśle powiązanych przypadków użycia.

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

Odpowiedź

cat filename.txt | grep smiths | awk -F "|" "{sum+=$NF} END {print sum}" 
  • -F opcja określająca separator .
  • $NF dotyczy „ostatniej kolumny”.

Komentarze

  • cat i grep są tutaj niepotrzebne.
  • Dlaczego grep jest niepotrzebny @Andrey? OP chce dodać tylko wiersze " smiths ". ' Czy musisz zmodyfikować instrukcję awk, prawda?
  • @EL tak, instrukcję awk należy zmienić na /smiths/{...} jeśli nie ma wywołania grep. Jest to trywialna modyfikacja, ale zapewnia znaczne korzyści: zmniejsza liczbę uruchomionych procesów, upraszcza kontrolę błędów i sprawia, że kod jest bardziej przejrzysty.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *