Perintah AWK berasal dari hari-hari awal Unix. Ini adalah bagian dari standar POSIX dan harus tersedia pada sistem mirip Unix. Dan seterusnya.
Meskipun terkadang didiskreditkan karena usianya atau kurangnya fitur dibandingkan dengan bahasa multiguna seperti Perl, AWK tetap menjadi alat yang saya suka gunakan dalam pekerjaan sehari-hari saya. Terkadang untuk menulis program yang relatif rumit, tetapi juga karena one-liner yang kuat, Anda dapat menulis untuk menyelesaikan masalah dengan file data Anda.
Jadi, inilah tepatnya tujuan artikel ini. Menunjukkan kepada Anda bagaimana Anda dapat memanfaatkan kekuatan AWK dalam waktu kurang dari 80 karakter untuk melakukan tugas yang bermanfaat. Artikel ini tidak dimaksudkan untuk menjadi tutorial AWK yang lengkap, tetapi saya masih menyertakan beberapa perintah dasar di awal sehingga meskipun Anda memiliki sedikit atau tanpa pengalaman sebelumnya, Anda dapat mengambil konsep inti AWK.
File sampel saya untuk tutorial AWK ini
Semua one-liner yang dijelaskan dalam artikel itu akan diuji pada file data yang sama:
cat file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Anda bisa mendapatkan salinan file tersebut secara online di GitHub.
Tahu variabel yang ditentukan sebelumnya dan otomatis di AWK
AWK mendukung beberapa variabel yang telah ditentukan sebelumnya dan otomatis untuk membantu Anda menulis program Anda. Diantaranya akan sering Anda temui:
RS –Pemisah rekaman. AWK memproses data Anda satu per satu. Pemisah record adalah pembatas yang digunakan untuk membagi aliran data input menjadi record. Secara default, ini adalah karakter baris baru. Jadi jika Anda tidak mengubahnya, sebuah record adalah satu baris dari file input.
NR – Nomor catatan masukan saat ini. Jika Anda menggunakan pembatas baris baru standar untuk catatan Anda, ini cocok dengan nomor baris input saat ini.
FS/OFS –Karakter yang digunakan sebagai pemisah bidang. Setelah AWK membaca catatan, AWK akan membaginya menjadi beberapa bidang berdasarkan nilai FS
. Ketika AWK mencetak catatan pada output, itu akan bergabung kembali dengan bidang, tetapi kali ini, menggunakan OFS
pemisah alih-alih FS
pemisah. Biasanya, FS
dan OFS
sama, tetapi ini tidak wajib. "spasi putih" adalah nilai default untuk keduanya.
NF – Jumlah bidang dalam catatan saat ini. Jika Anda menggunakan pembatas "spasi putih" standar untuk bidang Anda, ini akan cocok dengan jumlah kata dalam catatan saat ini.
Ada lebih atau kurang variabel AWK standar lain yang tersedia, jadi ada baiknya memeriksa manual implementasi AWK Anda untuk detail lebih lanjut. Namun, subset ini sudah cukup untuk mulai menulis satu kalimat yang menarik.
A. Penggunaan dasar perintah AWK
1. Cetak semua baris
Contoh ini sebagian besar tidak berguna, tetapi ini akan menjadi pengantar yang baik untuk sintaks AWK:
awk '1 { print }' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Program AWK dibuat dari satu atau banyak pattern { action }
pernyataan.
Jika, untuk rekaman yang diberikan (“baris”) dari file input, pola mengevaluasi ke nilai bukan nol (setara dengan "benar" di AWK), perintah di blok tindakan yang sesuai dieksekusi. Dalam contoh di atas, karena 1
adalah konstanta bukan nol, { print }
blok aksi dieksekusi untuk setiap record input.
Trik lainnya adalah { print }
adalah blok tindakan default yang akan digunakan oleh AWK jika Anda tidak secara eksplisit menentukannya. Jadi perintah di atas bisa disingkat menjadi:
awk 1 file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Hampir tidak berguna, program AWK berikut akan menggunakan inputnya tetapi tidak akan menghasilkan apa pun pada outputnya:
awk 0 file
2. Hapus header file
awk 'NR>1' file
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Ingat, ini setara dengan menulis secara eksplisit:
awk 'NR>1 { print }' file
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
One-liner ini akan menulis record dari file input kecuali yang pertama karena dalam kasus tersebut kondisinya adalah 1>1
yang jelas-jelas tidak benar.
Karena program ini menggunakan nilai default untuk RS
, dalam praktiknya akan membuang baris pertama dari file input.
3. Cetak garis dalam rentang
Ini hanya generalisasi dari contoh sebelumnya, dan tidak perlu banyak penjelasan, kecuali untuk mengatakan &&
adalah logika and
operator:
awk 'NR>1 && NR < 4' file
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
4. Menghapus garis khusus spasi
awk 'NF' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
AWK membagi setiap catatan menjadi beberapa bidang, berdasarkan pemisah bidang yang ditentukan dalam FS
variabel. Pemisah bidang default adalah satu atau beberapa karakter spasi putih (alias, spasi atau tab). Dengan pengaturan tersebut, catatan apa pun yang berisi setidaknya satu karakter non-spasi akan berisi setidaknya satu bidang.
Dengan kata lain, satu-satunya kasus di mana NF
adalah 0 ("salah") adalah ketika catatan hanya berisi spasi. Jadi, one-liner itu hanya akan mencetak record yang berisi setidaknya satu karakter non-spasi.
5. Menghapus semua baris kosong
awk '1' RS='' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
One-liner ini didasarkan pada aturan POSIX yang tidak jelas yang menentukan apakah RS
diatur ke string kosong, “maka record dipisahkan oleh urutan yang terdiri dari
Layak disebutkan dalam terminologi POSIX, baris kosong adalah baris yang benar-benar kosong. Baris yang hanya berisi spasi tidak dihitung sebagai "kosong".
6. Mengekstrak bidang
Ini mungkin salah satu kasus penggunaan paling umum untuk AWK:mengekstrak beberapa kolom file data.
awk '{ print $1, $3}' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
,
,
,
17,abhishek
Di sini, saya secara eksplisit mengatur pemisah bidang input dan output ke koma. Saat AWK membagi catatan menjadi beberapa bidang, AWK menyimpan konten bidang pertama menjadi $1, konten bidang kedua menjadi $2, dan seterusnya. Saya tidak menggunakannya di sini, tetapi perlu disebutkan $0 adalah keseluruhan catatan.
Dalam one-liner ini, Anda mungkin memperhatikan saya menggunakan blok tindakan tanpa pola. Dalam hal ini, 1 (“true”) diasumsikan untuk pola tersebut, sehingga blok tindakan dijalankan untuk setiap record.
Tergantung pada kebutuhan Anda, itu mungkin tidak menghasilkan apa yang kita inginkan untuk baris kosong atau spasi saja. Dalam hal ini, versi kedua itu bisa sedikit lebih baik:
awk 'NF { print $1, $3 }' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
,
17,abhishek
Dalam kedua kasus, saya memberikan nilai khusus untuk FS
dan OFS
pada baris perintah. Opsi lain adalah menggunakan BEGIN
special khusus blok di dalam program AWK untuk menginisialisasi variabel-variabel tersebut sebelum record pertama dibaca. Jadi, tergantung selera Anda, Anda mungkin lebih suka menulis itu:
awk 'BEGIN { FS=OFS="," } NF { print $1, $3 }' file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
,
17,abhishek
Perlu disebutkan di sini Anda juga dapat menggunakan END
blok untuk melakukan beberapa tugas setelah catatan terakhir dibaca. Seperti yang akan kita lihat sekarang. Meskipun demikian, saya akui ini jauh dari sempurna karena garis khusus spasi tidak ditangani dengan elegan. Kami akan segera melihat solusi yang mungkin, tetapi sebelum itu mari kita lakukan perhitungan…
7. Melakukan penghitungan berdasarkan kolom
AWK mendukung operator aritmatika standar. Dan akan mengonversi nilai antara teks dan angka secara otomatis tergantung pada konteksnya. Juga, Anda dapat menggunakan variabel Anda sendiri untuk menyimpan nilai antara. Semua itu memungkinkan Anda untuk menulis program ringkas untuk melakukan perhitungan pada kolom data:
awk '{ SUM=SUM+$1 } END { print SUM }' FS=, OFS=, file
263
Atau, secara setara menggunakan +=
sintaks singkatan:
awk '{ SUM+=$1 } END { print SUM }' FS=, OFS=, file
263
Harap dicatat variabel AWK tidak perlu dideklarasikan sebelum digunakan. Variabel yang tidak terdefinisi diasumsikan memegang string kosong. Yang menurut aturan konversi tipe AWK, sama dengan angka 0. Karena fitur itu, saya tidak repot-repot menangani secara eksplisit kasus di mana $1
berisi teks (dalam heading), spasi atau tidak sama sekali. Dalam semua kasus itu, itu akan dihitung sebagai 0 dan tidak akan mengganggu penjumlahan kami. Tentu saja, akan berbeda jika saya melakukan perkalian saja. Jadi, mengapa Anda tidak menggunakan bagian komentar untuk menyarankan solusi untuk kasus itu?
8. Menghitung jumlah baris yang tidak kosong
Saya telah menyebutkan END
aturan sebelumnya. Berikut adalah aplikasi lain yang mungkin untuk menghitung jumlah baris yang tidak kosong dalam sebuah file:
awk '/./ { COUNT+=1 } END { print COUNT }' file
9
Di sini saya menggunakan COUNT
variabel dan menambahkannya (+=1
) untuk setiap baris yang cocok dengan ekspresi reguler /./
. Artinya setiap baris mengandung setidaknya satu karakter. Terakhir, blok END digunakan untuk menampilkan hasil akhir setelah seluruh file diproses. Tidak ada yang istimewa dengan nama COUNT
. Saya bisa menggunakan Count
, count
, n
, xxxx
atau nama lain yang sesuai dengan aturan penamaan variabel AWK
Namun, apakah hasil ini benar? Yah, itu tergantung pada definisi Anda tentang garis "kosong". Jika Anda menganggap hanya baris kosong (menurut POSIX) yang kosong, maka ini benar. Tapi mungkin Anda lebih suka menganggap baris hanya spasi putih sebagai kosong juga?
awk 'NF { COUNT+=1 } END { print COUNT }' file
8
Kali ini hasilnya berbeda karena versi yang lebih baru mengabaikan baris hanya spasi putih juga, sedangkan versi awal hanya mengabaikan baris kosong. Dapatkah Anda melihat perbedaannya? Saya membiarkan Anda memikirkannya sendiri. Jangan ragu untuk menggunakan bagian komentar jika ini tidak cukup jelas!
Terakhir, jika Anda hanya tertarik pada baris data, dan dengan file data input khusus saya, saya dapat menulisnya sebagai gantinya:
awk '+$1 { COUNT+=1 } END { print COUNT }' file
7
Ini berfungsi karena aturan konversi tipe AWK. Unary plus dalam pola memaksa evaluasi $1 dalam konteks numerik. Di file saya, catatan data berisi nomor di bidang pertamanya. Catatan non-data (judul, baris kosong, baris hanya spasi putih) berisi teks atau tidak sama sekali. Semuanya sama dengan 0 saat dikonversi ke angka.
Perhatikan dengan solusi terbaru itu, catatan untuk pengguna yang akhirnya memiliki 0 kredit juga akan dibuang.
B. Menggunakan Array di AWK
Array adalah fitur canggih dari AWK. Semua larik di AWK adalah larik asosiatif, sehingga memungkinkan pengaitan string arbitrer dengan nilai lain. Jika Anda terbiasa dengan bahasa pemrograman lain, Anda mungkin mengenalnya sebagai hash , tabel asosiatif , kamus atau peta .
9. Contoh sederhana array AWK
Bayangkan saya ingin mengetahui total kredit untuk semua pengguna. Saya dapat menyimpan entri untuk setiap pengguna dalam larik asosiatif, dan setiap kali saya menemukan catatan untuk pengguna tersebut, saya menaikkan nilai terkait yang disimpan dalam larik.
awk '+$1 { CREDITS[$3]+=$1 }
END { for (NAME in CREDITS) print NAME, CREDITS[NAME] }' FS=, file
abhishek 17
sonia 129
öle 8
sylvain 109
Saya akui ini bukan lagi one-liner. Sebagian besar karena for
loop digunakan untuk menampilkan isi array setelah file diproses. Jadi, sekarang mari kembali ke contoh yang lebih singkat:
10. Mengidentifikasi garis duplikat menggunakan AWK
Array, seperti variabel AWK lainnya, dapat digunakan baik dalam blok tindakan maupun dalam pola. Dengan memanfaatkannya, kita dapat menulis satu baris untuk mencetak hanya baris duplikat:
awk 'a[$0]++' file
52,01 dec 2018,sonia,team
++
operator adalah operator pasca-kenaikan yang diwarisi dari keluarga bahasa C (yang AWK-nya adalah anggota yang bangga, terima kasih kepada Brian Kernighan yang menjadi salah satu penulis aslinya).
Seperti namanya, operator pasca-kenaikan menambahkan ("tambahkan 1") variabel, tetapi hanya setelah nilainya diambil untuk evaluasi ekspresi englobing.
Dalam hal ini, a[$0]
dievaluasi untuk melihat apakah record akan dicetak atau tidak, dan setelah keputusan dibuat, dalam semua kasus, entri array bertambah.
Jadi saat pertama kali record dibaca, a[$0]
tidak terdefinisi, dan dengan demikian setara dengan nol untuk AWK. Sehingga record pertama tidak tertulis pada output. Kemudian entri itu diubah dari nol menjadi satu.
Kedua kalinya record input yang sama dibaca, a[$0]
sekarang 1. Itu "benar". Garis akan dicetak. Namun, sebelum itu, entri array diperbarui dari 1 ke 2. Dan seterusnya.
11. Menghapus baris duplikat
Sebagai akibat wajar dari one-liner sebelumnya, kita mungkin ingin menghapus baris duplikat:
awk '!a[$0]++' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Satu-satunya perbedaan adalah penggunaan logika, bukan operator (!
) yang membalikkan nilai kebenaran dari ekspresi. Apa yang salah menjadi benar, dan apa yang benar menjadi salah. Logika tidak sama sekali tidak berpengaruh pada ++
kenaikan pos yang berfungsi persis seperti sebelumnya.
C. Keajaiban pemisah bidang dan rekaman
12. Mengubah pemisah bidang
awk '$1=$1' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
Program itu menyetel FS
dan OFS
variabel untuk menggunakan koma sebagai pemisah bidang input dan titik koma sebagai pemisah bidang keluaran. Karena AWK tidak mengubah catatan keluaran selama Anda tidak mengubah bidang, $1=$1
trik digunakan untuk memaksa AWK memecahkan rekor dan memasangnya kembali menggunakan pemisah bidang keluaran.
Ingat di sini blok tindakan default adalah { print }
. Jadi, Anda dapat menulis ulang itu secara lebih eksplisit sebagai:
awk '$1=$1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
Anda mungkin telah memperhatikan kedua contoh tersebut juga menghapus baris kosong. Mengapa? Nah, ingat aturan konversi AWK:string kosong adalah "salah." Semua string lainnya adalah "benar". Ekspresi $1=$1
adalah kepura-puraan yang mengubah $1
. Namun, ini juga ekspresi. Dan itu mengevaluasi nilai $1
–yang “salah” untuk string kosong. Jika Anda benar-benar menginginkan semua baris, Anda mungkin perlu menulis sesuatu seperti itu:
awk '($1=$1) || 1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
Apakah Anda ingat &&
operator? Itu logika DAN. ||
adalah logika OR. Tanda kurung diperlukan di sini karena aturan prioritas operator. Tanpa mereka, polanya akan salah ditafsirkan sebagai $1=($1 || 1)
sebagai gantinya. Saya biarkan sebagai latihan bagi Anda untuk menguji bagaimana hasilnya akan berbeda saat itu.
Terakhir, jika Anda tidak terlalu tertarik dengan aritmatika, saya yakin Anda akan memilih solusi yang lebih sederhana:
awk '{ $1=$1; print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
13. Menghapus banyak spasi
awk '$1=$1' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Ini adalah program yang hampir sama dengan yang sebelumnya. Namun, saya membiarkan pemisah bidang ke nilai defaultnya. Jadi, beberapa spasi digunakan sebagai pemisah kolom input, tetapi hanya satu spasi yang digunakan sebagai pemisah kolom output. Ini memiliki efek samping yang bagus dari penggabungan kelipatan spasi putih menjadi satu ruang.
14. Menggabungkan baris menggunakan AWK
Kami telah menggunakan OFS
, pemisah bidang keluaran. Seperti yang mungkin sudah Anda duga, ia memiliki ORS
mitra untuk menentukan pemisah catatan keluaran:
awk '{ print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle abhishek
Di sini, saya menggunakan spasi setelah setiap rekaman alih-alih karakter baris baru. One-liner ini cukup dalam beberapa kasus penggunaan, tetapi masih memiliki beberapa kekurangan.
Yang paling jelas, itu tidak membuang garis khusus spasi (spasi tambahan setelah öle berasal dari itu). Jadi, saya mungkin akan menggunakan ekspresi reguler biasa sebagai gantinya:
awk '/[^[:space:]]/ { print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle abhishek
Sekarang lebih baik, tetapi masih ada kemungkinan masalah. Akan lebih jelas jika kita mengubah pemisah menjadi sesuatu yang terlihat:
awk '/[^[:space:]]/ { print $3 }' FS=, ORS='+' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek+
Ada pemisah tambahan di akhir baris— karena pemisah bidang ditulis setelah setiap catatan. Termasuk yang terakhir.
Untuk memperbaikinya, saya akan menulis ulang program untuk menampilkan pemisah khusus sebelum catatan, mulai dari catatan keluaran kedua.
awk '/[^[:space:]]/ { print SEP $3; SEP="+" }' FS=, ORS='' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek
Karena saya sendiri yang akan menambahkan pemisah, saya juga menyetel pemisah catatan keluaran AWK standar ke string kosong. Namun, ketika Anda mulai berurusan dengan pemisah atau pemformatan, itu mungkin tanda yang harus Anda pertimbangkan untuk menggunakan printf
fungsi alih-alih print
penyataan. Seperti yang akan kita lihat sekarang.
D. Pemformatan bidang
Saya telah menyebutkan hubungan antara bahasa pemrograman AWK dan C. Antara lain, dari pustaka standar bahasa C, AWK mewarisi printf
. yang kuat fungsi, memungkinkan kontrol besar atas pemformatan teks yang dikirim ke output.
printf
function mengambil format sebagai argumen pertama, yang berisi teks biasa yang akan menjadi keluaran verbatim dan wildcard yang digunakan untuk memformat bagian keluaran yang berbeda. Wildcard diidentifikasi dengan %
karakter. Yang paling umum adalah %s
(untuk pemformatan string), %d
(untuk pemformatan bilangan bulat) dan %f
(untuk pemformatan angka floating point). Karena ini agak abstrak, mari kita lihat contohnya:
awk '+$1 { printf("%s ", $3) }' FS=, file; echo
sylvain sonia sonia sonia sylvain öle abhishek
Anda mungkin memperhatikan, sebagai kebalikan dari print
pernyataan, printf
fungsi tidak menggunakan OFS
dan ORS
nilai-nilai. Jadi, jika Anda menginginkan pemisah, Anda harus menyebutkannya secara eksplisit seperti yang saya lakukan dengan menambahkan karakter spasi di akhir string format. Ini adalah harga yang harus dibayar karena memiliki kendali penuh atas output.
Meskipun sama sekali bukan penentu format, ini adalah kesempatan yang sangat baik untuk memperkenalkan \n
notasi yang dapat digunakan dalam string AWK apa pun untuk mewakili karakter baris baru.
awk '+$1 { printf("%s\n", $3) }' FS=, file
sylvain
sonia
sonia
sonia
sylvain
öle
abhishek
15. Menghasilkan hasil tabel
AWK memberlakukan format data catatan/bidang berdasarkan pembatas. Namun, menggunakan printf
fungsi, Anda juga dapat menghasilkan output tabel lebar tetap. Karena setiap penentu format dalam printf
pernyataan dapat menerima parameter lebar opsional:
awk '+$1 { printf("%10s | %4d\n", $3, $1) }' FS=, file
sylvain | 99
sonia | 52
sonia | 52
sonia | 25
sylvain | 10
öle | 8
abhishek | 17
Seperti yang Anda lihat, dengan menentukan lebar setiap bidang, AWK melapisinya ke kiri dengan spasi. Untuk teks, biasanya lebih baik untuk menempatkan pad di sebelah kanan, sesuatu yang dapat dicapai dengan menggunakan angka lebar negatif. Juga, untuk bilangan bulat, kami mungkin ingin mengisi bidang dengan nol, bukan spasi. Ini dapat diperoleh dengan menggunakan 0 eksplisit sebelum lebar bidang:
awk '+$1 { printf("%-10s | %04d\n", $3, $1) }' FS=, file
sylvain | 0099
sonia | 0052
sonia | 0052
sonia | 0025
sylvain | 0010
öle | 0008
abhishek | 0017
16. Menangani bilangan floating point
%f
formatnya tidak perlu banyak penjelasan…
awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%f",SUM/NUM); }' FS=, file
AVG=37.571429
… kecuali mungkin untuk mengatakan bahwa Anda hampir selalu ingin secara eksplisit mengatur lebar bidang dan presisi dari hasil yang ditampilkan:
awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%6.1f",SUM/NUM); }' FS=, file
AVG= 37.6
Di sini, lebar bidang adalah 6, yang berarti bidang akan menempati ruang 6 karakter (termasuk titik, dan akhirnya diisi dengan spasi di sebelah kiri seperti biasanya). Presisi .1 berarti kita ingin menampilkan angka dengan 1 angka desimal setelah titik. Saya membiarkan Anda menebak apa %06.1
akan ditampilkan sebagai gantinya.
E. Menggunakan fungsi string di AWK
Selain printf
fungsi, AWK berisi beberapa fungsi manipulasi string bagus lainnya. Dalam domain itu, implementasi modern seperti Gawk memiliki serangkaian fungsi internal yang lebih kaya dengan harga portabilitas yang lebih rendah. Untuk saya sendiri, saya akan tetap di sini hanya dengan beberapa fungsi yang ditentukan POSIX yang seharusnya bekerja sama di mana saja.
17. Mengubah teks menjadi huruf besar
Yang ini, saya sering menggunakannya, karena menangani masalah internasionalisasi dengan baik:
awk '$3 { print toupper($0); }' file
99,01 JUN 2018,SYLVAIN,TEAM:::ADMIN
52,01 DEC 2018,SONIA,TEAM
52,01 DEC 2018,SONIA,TEAM
25,01 JAN 2019,SONIA,TEAM
10,01 JAN 2019,SYLVAIN,TEAM:::ADMIN
8,12 JUN 2018,ÖLE,TEAM:SUPPORT
17,05 APR 2019,ABHISHEK,GUEST
Faktanya, ini mungkin solusi terbaik dan paling portabel untuk mengonversi teks menjadi huruf besar dari shell.
18. Mengubah bagian dari string
Menggunakan substr
perintah, Anda dapat membagi string karakter pada panjang tertentu. Di sini saya menggunakannya untuk menggunakan huruf besar hanya pada karakter pertama dari kolom ketiga:
awk '{ $3 = toupper(substr($3,1,1)) substr($3,2) } $3' FS=, OFS=, file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,Sylvain,team:::admin
52,01 dec 2018,Sonia,team
52,01 dec 2018,Sonia,team
25,01 jan 2019,Sonia,team
10,01 jan 2019,Sylvain,team:::admin
8,12 jun 2018,Öle,team:support
17,05 apr 2019,Abhishek,guest
substr
function mengambil string awal, indeks (berbasis 1) dari karakter pertama yang diekstrak dan jumlah karakter yang akan diekstrak. Jika argumen terakhir tidak ada, substr
mengambil semua karakter string yang tersisa.
Jadi, substr($3,1,1)
akan mengevaluasi ke karakter pertama $3
, dan substr($3,2)
ke yang tersisa.
19. Memisahkan bidang dalam sub-bidang
Model data bidang rekaman AWK sangat bagus. Namun, terkadang Anda ingin membagi bidang itu sendiri menjadi beberapa bagian berdasarkan beberapa pemisah internal:
awk '+$1 { split($2, DATE, " "); print $1,$3, DATE[2], DATE[3] }' FS=, OFS=, file
99,sylvain,jun,2018
52,sonia,dec,2018
52,sonia,dec,2018
25,sonia,jan,2019
10,sylvain,jan,2019
8,öle,jun,2018
17,abhishek,apr,2019
Agak mengejutkan, ini berfungsi bahkan jika beberapa bidang saya dipisahkan oleh lebih dari satu spasi. Sebagian besar karena alasan historis, ketika pemisah adalah satu spasi, split
akan mempertimbangkan "elemen dipisahkan oleh spasi putih." Dan tidak hanya oleh satu orang saja. FS
variabel khusus mengikuti konvensi yang sama.
Namun, dalam kasus umum, satu karakter string cocok dengan satu karakter. Jadi, jika Anda membutuhkan sesuatu yang lebih kompleks, Anda harus ingat bahwa pemisah bidang adalah ekspresi reguler yang diperluas.
Sebagai contoh, mari kita lihat bagaimana menangani bidang grup yang tampaknya merupakan bidang multinilai menggunakan titik dua sebagai pemisah:
awk '+$1 { split($4, GRP, ":"); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team
sonia team
sonia team
sonia team
sylvain team
öle team support
abhishek guest
Padahal saya berharap untuk menampilkan hingga dua grup per pengguna, itu hanya menunjukkan satu untuk sebagian besar dari mereka. Masalah itu disebabkan oleh beberapa kejadian pemisah. Jadi, solusinya adalah:
awk '+$1 { split($4, GRP, /:+/); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team admin
sonia team
sonia team
sonia team
sylvain team admin
öle team support
abhishek guest
Garis miring alih-alih tanda kutip menunjukkan literal sebagai ekspresi reguler daripada string biasa, dan tanda plus menunjukkan ekspresi ini akan cocok dengan satu atau beberapa kemunculan karakter sebelumnya. Jadi, dalam hal ini, setiap pemisah dibuat (dari urutan terpanjang) satu atau beberapa titik dua berurutan.
20. Mencari dan mengganti dengan perintah AWK
Berbicara tentang ekspresi reguler, terkadang Anda ingin melakukan substitusi seperti sed s///g
perintah, tetapi hanya pada satu bidang. gsub
perintah adalah apa yang Anda butuhkan dalam kasus itu:
awk '+$1 { gsub(/ +/, "-", $2); print }' FS=, file
99 01-jun-2018 sylvain team:::admin
52 01-dec-2018 sonia team
52 01-dec-2018 sonia team
25 01-jan-2019 sonia team
10 01-jan-2019 sylvain team:::admin
8 12-jun-2018 öle team:support
17 05-apr-2019 abhishek guest
gsub
fungsi mengambil ekspresi reguler untuk mencari, string pengganti dan variabel yang berisi teks yang akan dimodifikasi di tempat. Jika nanti tidak ada, diasumsikan $0.
F. Bekerja dengan perintah eksternal di AWK
Fitur hebat lainnya dari AWK adalah Anda dapat dengan mudah menjalankan perintah eksternal untuk memproses data Anda. Pada dasarnya ada dua cara untuk melakukannya:menggunakan system
instruksi untuk menjalankan program dan membiarkannya mencampurkan outputnya dalam aliran output AWK. Atau menggunakan pipa agar AWK dapat menangkap output dari program eksternal untuk kontrol hasil yang lebih baik.
Itu mungkin topik yang sangat besar, tetapi berikut adalah beberapa contoh sederhana untuk menunjukkan kekuatan di balik fitur tersebut.
21. Menambahkan tanggal di atas file
awk 'BEGIN { printf("UPDATED: "); system("date") } /^UPDATED:/ { next } 1' file
UPDATED: Thu Feb 15 00:31:03 CET 2018
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
Dalam program AWK itu, saya mulai dengan menampilkan pekerjaan yang DIPERBARUI. Kemudian program memanggil date
external eksternal perintah, yang akan mengirimkan hasilnya pada output tepat setelah teks yang dihasilkan oleh AWK pada tahap itu.
Program AWK lainnya hanya menghapus pernyataan pembaruan yang akhirnya ada di file dan mencetak semua baris lainnya (dengan aturan 1
).
Perhatikan next
penyataan. Ini digunakan untuk membatalkan pemrosesan catatan saat ini. It is a standard way of ignoring some records from the input file.
22. Modifying a field externally
For more complex cases, you may need to consider the | getline VARIABLE
idiom of AWK:
awk '+$1 { CMD | getline $5; close(CMD); print }' CMD="uuid -v4" FS=, OFS=, file
99,01 jun 2018,sylvain,team:::admin,5e5a1bb5-8a47-48ee-b373-16dc8975f725
52,01 dec 2018,sonia,team,2b87e9b9-3e75-4888-bdb8-26a9b34facf3
52,01 dec 2018,sonia,team,a5fc22b5-5388-49be-ac7b-78063cbbe652
25,01 jan 2019,sonia,team,3abb0432-65ef-4916-9702-a6095f3fafe4
10,01 jan 2019,sylvain,team:::admin,592e9e80-b86a-4833-9e58-1fe2428aa2a2
8,12 jun 2018,öle,team:support,3290bdef-fd84-4026-a02c-46338afd4243
17,05 apr 2019,abhishek,guest,e213d756-ac7f-4228-818f-1125cba0810f
This will run the command stored in the CMD
variable, read the first line of the output of that command, and store it into the variable $5
.
Pay special attention to the close statement, crucial here as we want AWK to create a new instance of the external command each time it executes the CMD | getline
penyataan. Without the close statement, AWK would instead try to read several lines of output from the same command instance.
23. Invoking dynamically generated commands
Commands in AWK are just plain strings without anything special. It is the pipe operator that triggers external programs execution. So, if you need, you can dynamically construct arbitrary complex commands by using the AWK string manipulation functions and operators.
awk '+$1 { cmd = sprintf(FMT, $2); cmd | getline $2; close(cmd); print }' FMT='date -I -d "%s"' FS=, file
99 2018-06-01 sylvain team:::admin
52 2018-12-01 sonia team
52 2018-12-01 sonia team
25 2019-01-01 sonia team
10 2019-01-01 sylvain team:::admin
8 2018-06-12 öle team:support
17 2019-04-05 abhishek guest
We have already met the printf
fungsi. sprintf
is very similar but will return the built string rather than sending it to the output.
24. Joining data
To show you the purpose of the close statement, I let you try out that last example:
awk '+$1 { CMD | getline $5; print }' CMD='od -vAn -w4 -t x /dev/urandom' FS=, file
99 01 jun 2018 sylvain team:::admin 1e2a4f52
52 01 dec 2018 sonia team c23d4b65
52 01 dec 2018 sonia team 347489e5
25 01 jan 2019 sonia team ba985e55
10 01 jan 2019 sylvain team:::admin 81e9a01c
8 12 jun 2018 öle team:support 4535ba30
17 05 apr 2019 abhishek guest 80a60ec8
As the opposite of the example using the uuid
command above, there is here only one instance of od
launched while the AWK program is running, and when processing each record, we read one more line of the output of that same process.
Conclusion
That quick tour of AWK certainly can’t replace a full-fledged course or tutorial on that tool. However, for those of you that weren’t familiar with it, I hope it gave you enough ideas so you can immediately add AWK to your toolbox.
On the other hand, if you were already an AWK aficionado, you might have found here some tricks you can use to be more efficient or simply to impress your friends.
However, I do not pretend been exhaustive. So, in all cases, don’t hesitate to share your favorite AWK one-liner or any other AWK tips using the comment section below!