Perintah awk Linux: pilih kolom, saring baris, dan jumlahkan data

Perintah awk membaca teks sebagai rekaman dan bidang, lalu memilih, menampilkan, atau menghitung nilai yang memenuhi kondisi. Gunakan awk untuk mengambil kolom, menyaring baris, dan menjumlahkan data terstruktur. Sebelum menghitung, tentukan pemisah, perlakuan terhadap header, dan bentuk angka yang sah agar hasil tidak menyesatkan.

Rekaman, bidang, dan sintaks dasar

Secara bawaan, satu baris masukan menjadi satu rekaman. Rekaman dipecah menjadi bidang berdasarkan spasi atau tab; deretan pemisah tersebut diperlakukan sebagai satu pemisah dan spasi atau tab di awal serta akhir tidak menghasilkan bidang kosong. Pemisahan bawaan ini berbeda dari memilih pemisah tertentu secara eksplisit dengan -F.

awk [OPSI] 'POLA { AKSI }' [BERKAS...]

OPSI dan BERKAS adalah penanda yang perlu diganti. POLA menentukan rekaman yang diproses, sedangkan AKSI di dalam kurung kurawal menentukan pekerjaannya. Tanpa pola, aksi dijalankan pada setiap rekaman. Tanpa aksi, pola yang cocok mencetak rekaman lengkap. Jika berkas tidak disebutkan, awk membaca masukan standar, misalnya keluaran perintah lain melalui pipa.

Gunakan tanda kutip tunggal di shell agar $1 atau $2 di dalam program awk tidak lebih dahulu dikembangkan oleh shell. Periksa man awk pada sistem Anda: GNU gawk, mawk, dan implementasi lain dapat menyediakan opsi atau perluasan yang berbeda.

  • $0 berarti rekaman lengkap, termasuk spasi atau tab aslinya selama rekaman belum dibangun ulang.
  • $1 dan $2 berarti bidang pertama dan kedua. NF menyatakan jumlah bidang pada rekaman saat ini.
  • NR menghitung seluruh rekaman yang sudah dibaca. FNR menghitung rekaman pada berkas saat ini dan dimulai kembali ketika berkas berikutnya dibaca.

Bandingkan kolom, kondisi, dan jumlah pada satu masukan

Jalankan seluruh blok berikut di Bash atau shell yang mendukung sintaksnya. Mktemp membuat direktori latihan baru, dan semua berkas disiapkan di sana. Tanda kurung menjalankan perubahan direktori dalam subshell, sehingga direktori kerja semula tetap sama. Lokasi berkas latihan dicetak setelah teks Lab files: pada akhir blok.

(
set -eu
labdir=$(mktemp -d)
cd "$labdir"
printf 'name amount\nAna 12\nBob 7\nCara 11\n' > amounts.txt
awk 'NR > 1 {print $2}' amounts.txt
awk 'NR > 1 && $2 >= 10 {print $1}' amounts.txt
awk 'NR > 1 {sum += $2} END {print sum}' amounts.txt
printf 'Dana missing\n' >> amounts.txt
awk 'NR == 1 {next}
     NF != 2 || $2 !~ /^[0-9]+([.][0-9]+)?$/ {
         print "invalid row " NR ": " $0 > "/dev/stderr"
         bad = 1; next
     }
     {sum += $2}
     END {if (bad) exit 1; print sum}' amounts.txt || test "$?" -eq 1
printf 'Lab files: %s\n' "$labdir"
)

Hasil yang perlu diperiksa, sesuai urutan perintah:

  1. Pemilihan bidang kedua menampilkan 12, 7, lalu 11 pada baris terpisah. Kondisi NR > 1 melewati header.
  2. Penyaringan nilai minimal 10 menampilkan Ana dan Cara. Nilai milik Bob adalah 7 sehingga tidak dipilih.
  3. Penjumlahan menghasilkan 30. Aksi biasa menambahkan tiap nilai ke sum, lalu END mencetak hasil setelah seluruh masukan selesai.
  4. Sesudah Dana missing ditambahkan, validator menulis invalid row 5: Dana missing ke galat standar. Validator tidak mencetak jumlah yang seolah-olah berhasil untuk data tersebut.

Berkas amounts.txt pada akhir blok sengaja mengandung baris tidak valid. Untuk mengulang contoh perhitungan dengan data bersih, pindah ke direktori yang dicetak tadi dengan cd "/jalur/latihan-yang-dicetak", ganti penanda jalurnya, lalu jalankan printf 'name amount\nAna 12\nBob 7\nCara 11\n' > valid.txt. Berkas baru valid.txt dipakai dalam contoh lanjutan di bawah; jangan menimpa berkas penting dengan nama itu.

Mengapa angka perlu divalidasi?

Penjumlahan sederhana bukan pemeriksaan mutu data. Dalam konteks aritmetika, string dapat dikonversi menjadi angka; misalnya string tanpa awalan angka dapat diperlakukan sebagai nol. Karena itu, hasil penjumlahan yang tampak masuk akal belum membuktikan bahwa semua nilai masukan sah.

Validator pada blok memeriksa bahwa setiap baris data mempunyai tepat dua bidang dan bidang kedua cocok dengan ekspresi reguler ^[0-9]+([.][0-9]+)?$. Bentuk ini menerima bilangan nonnegatif seperti 12 atau 12.5 dengan titik desimal. Bentuk tersebut menolak tanda minus, notasi eksponen, koma desimal, nilai hilang, serta bidang tambahan. Jika format data Anda berbeda, sesuaikan aturan dan cara pembacaan angkanya.

Variabel bad menandai kesalahan. Perintah next melewati aksi berikutnya untuk baris yang salah, tetapi pemrosesan baris lain diteruskan. Pada END, if (bad) exit 1 mengakhiri program dengan status gagal sebelum print sum. Pesan galat menggunakan /dev/stderr pada lingkungan GNU yang dipakai contoh.

Bentuk || test "$?" -eq 1 hanya menerima status 1 yang sengaja dihasilkan latihan agar blok dapat mencetak lokasi bahan latihan. Dalam pekerjaan nyata, jangan menjadikannya pola untuk menganggap validasi gagal sebagai sukses. Periksa status awk dan hentikan langkah yang memerlukan data bersih. Pemeriksaan ini juga belum memvalidasi isi header, mensyaratkan adanya baris data, atau menjamin ketepatan aritmetika untuk kebutuhan keuangan.

Pemisah, variabel, dan keluaran

Pilih pemisah berdasarkan format data

Untuk teks sederhana berformat nama:nilai, printf 'Ana:12\nBob:7\n' | awk -F: '{print $1, $2}' menghasilkan Ana 12 dan Bob 7. Koma di dalam perintah print memisahkan ekspresi keluaran; spasi di antara hasil berasal dari pemisah keluaran OFS, bukan dari -F.

Dengan pemisah titik dua, printf 'Ana::12\n' | awk -F: '{print NF, "[" $2 "]"}' menghasilkan 3 []: dua titik dua berurutan menyisakan bidang kedua kosong. Jangan menganggap semua jenis pemisah akan merapatkan deretan karakter seperti pemisahan spasi bawaan.

Gunakan -v untuk nilai dari luar program

Di direktori latihan dengan valid.txt yang sudah disiapkan, awk -v batas=10 'NR > 1 && $2 >= batas {print $1}' valid.txt memilih Ana dan Cara. Ubah batas menjadi 12 pada masukan yang sama untuk mendapatkan Ana saja, lalu kembalikan ke 10 untuk membandingkan hasil. Opsi -v menetapkan variabel sebelum BEGIN dijalankan.

Untuk menambahkan label awal dan hasil akhir, awk 'BEGIN {print "total"} NR > 1 {sum += $2} END {print sum}' valid.txt mencetak total, kemudian 30. BEGIN tidak menunggu rekaman pertama, sedangkan END memproses hasil akhir setelah pembacaan masukan.

Jika menggabungkan beberapa berkas yang masing-masing mempunyai header, NR > 1 hanya melewati baris pertama seluruh masukan. Contohnya, awk 'FNR > 1 {print $1}' valid.txt valid.txt melewati header pada kedua pembacaan dan mencetak Ana, Bob, Cara dua kali. Sesuaikan pilihan NR atau FNR dengan struktur berkas Anda.

Simpan hasil ke tujuan yang berbeda

Awk biasanya menulis hasil ke keluaran standar tanpa mengubah masukan. Perintah awk 'NR > 1 {print $1}' valid.txt > names.txt menyimpan tiga nama ke names.txt. Pastikan tujuan belum berisi data yang perlu dipertahankan karena > dapat menimpa isinya. Jangan mengalihkan hasil ke valid.txt yang sedang dibaca: shell dapat mengosongkannya sebelum awk mulai membaca.

Opsi dan bentuk yang sering digunakan

Opsi atau bentuk Kegunaan
-F PEMISAH Menentukan pemisah bidang masukan melalui FS.
-v nama=nilai Menetapkan variabel sebelum program, termasuk BEGIN, dijalankan.
BEGIN { aksi } Menjalankan persiapan sebelum rekaman masukan dibaca.
END { aksi } Menjalankan pengolahan akhir; aksi END juga dapat dijalankan setelah exit dari pemrosesan rekaman.
NR / FNR / NF Jumlah rekaman keseluruhan, nomor rekaman per berkas, dan jumlah bidang saat ini.

Batas pemisahan CSV dan perbedaan implementasi

Comma-separated values (CSV) adalah format data dengan pemisah koma yang juga mempunyai aturan tanda kutip. Memakai -F, saja hanya memisahkan koma; cara itu tidak memahami koma di dalam bidang bertanda kutip. Misalnya, printf '"Ana, A",12\n' | awk -F, '{print NF}' menghasilkan 3, padahal rekaman CSV tersebut mempunyai dua bidang.

Gunakan pembaca CSV yang sesuai. Manual GNU gawk 5.4 yang ditayangkan di man7 mendokumentasikan mode --csv atau -k untuk tanda kutip, koma, dan baris baru di dalam bidang. Pada gawk yang menyediakan opsi itu, printf '"Ana, A",12\n' | gawk --csv '{print NF, $1, $2}' menghasilkan 2 Ana, A 12. Opsi GNU ini tidak tersedia pada setiap perintah bernama awk; periksa versi dan bantuan sebelum menggunakannya.

Contoh aritmetika di atas memakai titik desimal dan data sederhana. Untuk angka menurut lokal tertentu, CSV rumit, nilai sangat besar, atau kebutuhan ketepatan khusus, tentukan format dan kemampuan alat terlebih dahulu. Memecah teks menjadi bidang saja belum sama dengan memvalidasi seluruh format data.

FAQ

Apa perbedaan $0 dan $1?

$0 adalah rekaman lengkap, sedangkan $1 adalah bidang pertama setelah pemisahan. Mencetak $1 dan $2 memakai OFS di antara hasil; mengubah isi bidang juga dapat membangun ulang $0 dengan pemisah keluaran, sehingga spasi aslinya tidak selalu dipertahankan.

Mengapa tidak ada hasil walaupun awk berhasil?

Pola mungkin tidak cocok dengan rekaman mana pun. Tidak adanya kecocokan biasanya tetap berstatus sukses; jika pekerjaan mensyaratkan adanya data yang cocok, tambahkan pemeriksaan jumlah hasil dan tentukan status gagal yang sesuai.