Menggunakan awk untuk menjumlahkan nilai-nilai kolom, berdasarkan nilai-nilai kolom lain

64

Saya mencoba menjumlahkan angka-angka tertentu dalam kolom menggunakan awk. Saya ingin menjumlahkan hanya kolom 3 dari "pandai besi" untuk mendapatkan total 212. Saya bisa menjumlahkan seluruh kolom menggunakan awktetapi tidak hanya "pandai besi". Saya sudah:

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

Saya juga menggunakan dempul. Terima kasih atas bantuannya.

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

Jawaban:

82
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • The -Fbendera menetapkan pemisah lapangan; Saya menuliskannya dalam tanda kutip tunggal karena ini adalah karakter shell khusus.
  • Kemudian $1 ~ /smiths/menerapkan {code block} berikut ini hanya untuk baris di mana bidang pertama cocok dengan regex /smiths/.
  • Sisanya sama dengan kode Anda.

Perhatikan bahwa karena Anda tidak benar-benar menggunakan regex di sini, hanya nilai tertentu, Anda dapat dengan mudah menggunakan:

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

Yang memeriksa kesetaraan string. Ini sama dengan menggunakan regex /^smiths$/, seperti yang disebutkan dalam jawaban lain, yang mencakup ^jangkar untuk hanya cocok dengan awal string (awal bidang 1) dan $jangkar untuk hanya cocok dengan ujung string. Tidak yakin seberapa akrab Anda dengan regex. Mereka sangat kuat, tetapi untuk kasus ini Anda dapat menggunakan pemeriksaan kesetaraan string dengan mudah.

Wildcard
sumber
3
Ngomong-ngomong, referensi awk favorit saya adalah grymoire.com/Unix/Awk.html . Halaman sangat membantu
Wildcard
1
@Wildcard terima kasih! Saya dapat dengan rapi mengumpulkan ukuran tertentu dari file-file tertentu dalam arsip zip besar berdasarkan saran Anda :) unzip -lv /appl/tmp/data.lar | grep documentlibrary | awk '{sum += $1} END {print sum/1024/1024}'
Pawel
15

Pendekatan lain adalah dengan menggunakan array asosiatif awk, info lebih lanjut di sini . Baris ini menghasilkan output yang diinginkan:

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

Sebagai efek samping, array menyimpan semua nilai lain:

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

Keluaran:

smiths 212
denniss 100
olivert 10
Andrey
sumber
Ini adalah jawaban yang tepat
PoVa
5

Sangat bagus sejauh ini. Yang perlu Anda lakukan adalah menambahkan pemilih sebelum blok untuk menambahkan jumlahnya. Di sini kami memeriksa bahwa argumen pertama hanya berisi "pandai besi":

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

Anda bisa mempersingkat ini sedikit dengan menetapkan pemisah bidang sebagai opsi. Pada awkumumnya ide yang bagus untuk menginisialisasi variabel pada baris perintah:

awk -F'|' '$1 ~ /^smiths$/ {sum+=$3} END {print sum}'
RobertL
sumber
0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F pilihan untuk menentukan pemisah.
  • $NF adalah untuk "kolom terakhir".
forzagreen
sumber
1
catdan greptidak perlu di sini.
Andrey
Mengapa grep @Andrey tidak dibutuhkan? OP ingin menambahkan hanya baris "pandai besi". Anda perlu memodifikasi pernyataan awk, bukan?
EL
1
@EL ya, pernyataan awk harus diubah ke /smiths/{...}jika panggilan grep tidak ada. Ini adalah modifikasi sepele, tetapi memberikan manfaat yang signifikan: mengurangi jumlah proses yang berjalan, menyederhanakan kontrol kesalahan, dan membuat kode lebih jelas.
Andrey
0

Saya pribadi lebih suka menjaga awkbagian sesederhana mungkin dan melakukan sebanyak yang Anda bisa tanpanya. Comingled logic tidak mengambil keuntungan dari kekuatan jaringan pipa Unix dan karenanya lebih sulit untuk memahami, men-debug atau memodifikasi untuk kasus penggunaan yang terkait erat.

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