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
igrep
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.