- GNU
awk secara otomatis menelusuri stdin dan file, serta menangani pekerjaan teks CLI dengan menggabungkan pemfilteran, substitusi, dan pemrosesan field dalam perintah satu baris
/regexp/ dan !/regexp/ adalah sintaks singkat untuk memeriksa baris input saat ini; jika kondisinya benar, secara default $0 akan dicetak
sub hanya mengganti kecocokan pertama, sedangkan gsub mengganti semua kecocokan; jika target dihilangkan, substitusi diterapkan pada baris input saat ini $0
- Berkat pemisahan field berbasis spasi serta
$N, NF, dan $NF, awk sangat cocok untuk pekerjaan berbasis field seperti memilih kolom tertentu atau memprosesnya dengan kondisi
- Dengan merangkai potongan
cond{action} lalu menambahkan BEGIN{} dan END{}, Anda dapat membuat program kecil yang melampaui filter sederhana, mencakup string, angka, hingga array asosiatif
Cara kerja eksekusi awk
awk dapat memfilter teks seperti grep dan sed, sekaligus menyediakan fitur pemrograman untuk pemrosesan yang lebih kompleks
- Input dapat diterima dari stdin atau file, dan secara default diproses baris demi baris sambil menerapkan kondisi dan aksi
- Seluruh baris input diakses melalui variabel khusus
$0
- Istilah yang tepat adalah record input, tetapi dalam bab ini penjelasannya dibahas per baris
Pemfilteran dan output default
- Ekspresi reguler ditulis dalam bentuk
/.../, dan saat memeriksa apakah sebuah string cocok dengan ekspresi reguler, gunakan sintaks string ~ /regexp/
- Kondisi kebalikannya dinyatakan dengan
string !~ /regexp/
- Jika string yang akan diperiksa dihilangkan,
$0 menjadi targetnya
- Jika hanya ada kondisi tanpa aksi,
$0 otomatis dicetak saat kondisi bernilai benar
awk '/regexp/' adalah bentuk singkat dari awk '$0 ~ /regexp/{print $0}'
awk '!/regexp/' adalah bentuk singkat dari awk '$0 !~ /regexp/{print $0}'
- Contoh menunjukkan alur pemfilteran dasar dengan mencetak hanya baris yang berisi
at, atau hanya baris yang tidak berisi e
Output idiomatis dengan 1
- Dalam ekspresi kondisi, angka bukan nol dan string yang tidak kosong dievaluasi sebagai benar
awk '1' adalah ungkapan idiomatis yang memberikan kondisi yang selalu benar untuk semua baris input
- Karena kondisi benar tanpa aksi berujung pada pencetakan
$0, awk '1' mencetak seluruh input apa adanya
- Hasilnya sama dengan
awk '{print $0}' atau cat sederhana
Substitusi: sub dan gsub
awk menyediakan fungsi sub dan gsub untuk pencarian dan substitusi
sub(/:/, "-") mengganti hanya : pertama pada setiap baris input menjadi -
gsub(/:/, "-") mengganti semua : pada setiap baris input menjadi -
- Kedua fungsi menerima ekspresi reguler yang akan dicocokkan sebagai argumen pertama, dan string pengganti sebagai argumen kedua
- Jika string input tidak diberikan secara terpisah, target defaultnya adalah
$0
- Jika substitusi berhasil, input target akan dimodifikasi
1 setelah blok substitusi ditafsirkan sebagai ekspresi kondisi di luar blok, sehingga $0 yang telah dimodifikasi dicetak kembali
awk '{sub(/:/, "-")} 1' menghasilkan hasil yang sama dengan awk '{sub(/:/, "-"); print $0}'
- Dengan hanya menulis
print, target output defaultnya juga $0
Kriteria memilih grep, sed, atau awk
- Untuk pemfilteran baris sederhana,
grep yang dioptimalkan untuk tujuan tersebut bisa lebih cepat daripada sed atau awk
- Untuk pekerjaan substitusi,
sed bisa lebih cepat daripada awk
- Fitur antaralat tidak selalu berpadanan 1:1
- Untuk mengimplementasikan
grep -o dengan sed atau awk, diperlukan lebih banyak langkah
- Pencarian rekursif hanya disediakan oleh
grep
- Diskusi terkait dapat dilihat di unix.stackexchange: When to use grep, sed, awk, perl, etc
Pemrosesan berbasis field
awk terutama sering digunakan untuk pemrosesan berbasis field
- Secara default, baris input dibagi berdasarkan spasi, dan setiap field diakses dengan
$N
$2 adalah field kedua
$NF adalah field terakhir
NF adalah jumlah seluruh field pada baris input saat ini
- Contoh
table.txt menunjukkan pemrosesan per kolom secara ringkas
- Mencetak field kedua dari setiap baris
- Mencetak hanya baris yang field terakhirnya negatif
- Mengubah
b menjadi B hanya pada field pertama
- File contoh ada di direktori example_files
Struktur perintah satu baris
- Perintah satu baris
awk umumnya memiliki bentuk berikut
awk 'cond1{action1} cond2{action2} ... condN{actionN}'
- Jika tidak ada kondisi, aksi selalu dijalankan
- Jika tidak ada aksi,
$0 dicetak saat kondisi bernilai benar
- Di dalam blok, beberapa pernyataan dapat dipisahkan dengan titik koma
;
- Dengan merangkai beberapa blok, pada sebagian besar perintah satu baris Anda dapat mengekspresikan aksi per kondisi tanpa
if eksplisit
awk '$NF<0' table.txt mencetak hanya baris yang field terakhirnya negatif
BEGIN{} dijalankan sebelum input dibaca
END{} dijalankan setelah semua pemrosesan input selesai
- Detail tentang operator dan ekspresi kondisi tersedia di gawk manual: Operators, gawk manual: Truth Values and Conditions
String dan angka
awk menentukan tipe nilai berdasarkan konteks agar dapat membuat solusi singkat di CLI
- Literal string ditulis di dalam tanda kutip ganda
- Angka dapat menggunakan bilangan bulat, floating point, dan notasi ilmiah
BEGIN{} juga dapat digunakan untuk menjalankan program awk tanpa input eksternal
- Variabel dapat menyimpan angka dan string
- Contoh:
a=5; b=2.5; print a+b
- Meletakkan string berdampingan akan menggabungkannya
- Variabel yang belum diinisialisasi berperilaku seperti string kosong dalam konteks string, dan seperti
0 dalam konteks angka
- Jika string digunakan dalam ekspresi angka, string tersebut dikonversi paksa menjadi angka
- Jika string tidak diawali angka yang valid, string diperlakukan sebagai
0
- Spasi di bagian depan diabaikan
- Jika angka digabungkan dengan string, angka dikonversi menjadi string
- Detail selengkapnya tersedia di gawk manual: Constant Expressions dan gawk manual: How awk Converts Between Strings and Numbers
Array
- Array
awk adalah array asosiatif dan bekerja sebagai pasangan kunci-nilai
- Kunci dapat berupa angka atau string, tetapi kunci angka secara internal dikonversi menjadi string
- Array multidimensi juga dapat digunakan
- Dalam contoh, nilai disimpan dan diakses dengan kunci string seperti
student["id"] dan student["name"]
- Keberadaan kunci diperiksa dalam bentuk
"id" in student
- Detail selengkapnya tersedia di gawk manual: Arrays
Latihan dan langkah berikutnya
- Bab ini secara singkat memperkenalkan singkatan dasar sintaks
awk, pemfilteran, substitusi, pemrosesan field, konversi tipe, dan array
- Bab berikutnya membahas ekspresi reguler, dan fitur-fitur yang diperkenalkan dalam bab ini akan terus digunakan dalam contoh
- Anda dapat membiasakan diri dengan sintaks ini dengan mengubah nomor field, atau bereksperimen dengan input lain seperti field bernilai negatif dan floating point
- Aplikasi TUI untuk latihan interaktif dapat dipasang dari repositori AwkExercises, dan cara penggunaannya tersedia di app_guide.md
- Semua soal latihan dikumpulkan di Exercises.md, dan jawabannya tersedia di Exercise_solutions.md
1 komentar
Komentar Hacker News
Saya suka awk dan cukup sering memakainya; salah satu penggunaan utamanya adalah seperti sed yang memiliki state
Misalnya, mencocokkan suatu baris hanya ketika baris itu muncul setelah baris tertentu sebelumnya, jadi berguna saat membuat linter sementara
Baru-baru ini saya membuat pemeriksaan untuk mencari file migrasi yang berisi
CREATE INDEXyang berpotensi bermasalah pada tabel yang sangat besar karena tidak memakaiCONCURRENTLY; karena pernyataan SQL bisa membentang beberapa baris, pencocokan sederhana jadi sulitawk bisa melakukan pelacakan state lintas beberapa baris seperti “sedang berada di dalam pernyataan create” atau “sedang membuat indeks”, jadi skrip yang dirangkai seadanya itu sudah berjalan baik sekitar 1 tahun
Untuk mencetak baris saat ini hanya jika baris sebelumnya cocok dengan pola tertentu, bisa dilakukan seperti
sed -ne 'x' -e '/PREV/ {x; /CURR/ p; x}'Contoh:
echo -e "PREV\nCURR\nCURR\nCURR\nPREV\nRED" | sed -ne 'x' -e '/PREV/ {x; /CURR/ p; x}'hanya mencetakCURRIni adalah cara menggunakan hold buffer di sed;
-nmenonaktifkan keluaran default, laluphanya mencetak baris yang diperlukanxmenukar baris saat ini dengan hold buffer, lalu di dalam blok/PREV/ { ... }menukarnya lagi dan hanya mencetak jika baris saat ini berisiCURRxterakhir dipakai untuk mengembalikannya lagi bila ada kecocokan yang saling tumpang tindihTentu saja skrip awk kemungkinan besar jauh lebih sederhana dan langsung, tetapi sed juga bisa melakukan hal seperti ini
Mungkin waktu untuk mempelajari ini lebih baik dipakai untuk awk, tetapi tutorial https://www.grymoire.com/Unix/Sed.html sangat bagus sehingga hampir semua yang saya ketahui tentang sed saya pelajari dari sana
Orang yang membaca thread ini mungkin juga tertarik pada “Ask HN: Share a shell script you like” dari 2 minggu lalu
Komentarnya hanya 78, jadi tidak seramai yang diharapkan, tetapi cukup layak dijadikan referensi: https://news.ycombinator.com/item?id=37112991
Ada juga tulisan dari tahun lalu: https://news.ycombinator.com/item?id=32467957 (374 poin, 294 komentar)
Bersama Lisp dan lainnya, saya juga tetap menyimpan sedikit minat pada Awk, dan pada 2022 saya membuat cppawk: https://www.kylheku.com/cgit/cppawk/about/
cppawk memperluas Awk dengan fitur praproses
Ada makro loop yang mendukung beberapa klausa; klausa dapat dikombinasikan untuk membuat iterasi paralel atau iterasi produk Kartesius, dan juga bisa diperluas oleh pengguna
Dengan menulis 5 makro sederhana, Anda bisa mendefinisikan klausa baru
Jika Anda memakai Awk, ini mungkin berguna; dokumentasinya tersedia dalam beberapa man page, dan ada unit test yang berjalan di gawk dan mawk
Mungkin ini menunjukkan naluri administrator sistem zaman dulu, tetapi saya tidak begitu paham apa keunggulan awk dibanding sekadar menulis hal yang sama dengan Perl
Saya pernah melihat banyak skrip shell mengerikan yang dibuat oleh administrator sistem junior, dan setiap kali saya berpikir, “bagian pemrosesan teksnya pasti jauh lebih rapi kalau memakai Perl”
Bagi saya, awk adalah salah satu dari sedikit bahasa yang meski ditinggalkan selama berbulan-bulan, dalam 10 menit saya sudah bisa kembali mengingatnya
Ada sisi yang intuitif, dan cocok secara alami dengan alat baris perintah umum
Namun tulisan ini membahas perintah satu baris pendek untuk kebutuhan sementara, dan dalam kasus seperti itu sed/awk lebih baik daripada Perl
Jika Anda sudah tahu Perl, tidak perlu mempelajari alat tambahan; terus saja memakai Perl
Sebagai bahasa, ia hanya “lumayan”, tetapi cukup layak dipakai
Tentu Perl juga bisa melakukan semuanya, tetapi Anda harus menulis sendiri boilerplate yang awk berikan secara gratis
Keunggulan bahasa Perl bagi saya tidak cukup besar untuk meninggalkan awk, dan karena saya memakai awk terutama untuk pemrosesan data dan pengolahan file sekali pakai ketimbang “scripting”, saya tidak merasa kekurangan kedalaman Perl
Jika butuh fitur yang lebih dalam, saya pergi ke tempat lain
Karena generasi sekarang tidak belajar Perl, mereka tampaknya menemukan kembali gagasan pemrosesan stream lewat awk
awk adalah ide yang bagus untuk standar akhir 1970-an, dan benar-benar merupakan inovasi yang layak ditiru
Setelah itu Perl meniru dan melampauinya, tetapi kemudian terlupakan; jadi agak canggung melihat awk ditemukan kembali
Salah satu hal yang kurang dikenal di gawk adalah biasanya ia disertai ekstensi yang berguna
Anda bisa mengakses fungsi seperti
readdir(),ord(),chr(),gettimeofday(),sleep()https://www.gnu.org/software/gawk/manual/html_node/Extension-Samples.html
Perintah satu baris awk memang sangat kuat
Pertanyaan sulitnya adalah apakah layak berinvestasi pada pemrograman awk yang lebih kompleks
Jika tugas pemrosesan menuntut logika yang rumit, awk memang menyediakannya, tetapi dalam gaya era komputasi awal yang singkat dan sulit dipahami
Namun jika memilih alternatif modern, itu juga ada bebannya, terutama bisa jadi tidak intuitif seperti pandas, dan bahkan bisa menimbulkan masalah performa
Bahkan file fungsi umum untuk pribadi pun rasanya tidak didukung dengan baik, dan tampaknya tidak ada cara yang memadai untuk mengambil library pihak ketiga
Begitu saya membutuhkan fungsi helper dan mulai memecahnya menjadi beberapa baris, biasanya saya pindah ke Python
Lalu programnya menjadi 2–3 kali lebih besar dan saya pun menghela napas
Ruby adalah pengganti awk yang sangat bagus, tetapi jika rekan kerja tidak mengenal Ruby, sulit berharap mereka bisa memeliharanya
Sekarang, kalau perintah yang sulit dibaca seperti itu ditempelkan ke AI, penjelasan langkah demi langkahnya cukup baik, jadi sudah lebih bisa diterima
Meski begitu, karena bisa dibuat unit test, saya masih lebih suka beberapa baris Python, tetapi untuk pekerjaan pengolahan data cepat, sering kali unit test memang tidak diperlukan sejak awal
Merilis versi baru ebook “CLI text processing with GNU awk”
Anda bisa mempelajari perintah
GNU awksecara bertahap dari pemula hingga mahir melalui ratusan contoh dan latihan; isinya membahas secara mendalam pemrosesan field, filtering, pemrosesan banyak file, solusi yang bergantung pada banyak record, perbandingan record·field antarfile, pencarian duplikat sambil mempertahankan urutan input, ekspresi reguler, dan lain-lainPDF/EPUB: https://learnbyexample.gumroad.com/l/gnu_awk (gratis sampai 31 Agustus 2023)
Versi web: https://learnbyexample.github.io/learn_gnuawk/
Sumber Markdown dan file contoh: https://github.com/learnbyexample/learn_gnuawk
Aplikasi TUI interaktif untuk latihan: https://github.com/learnbyexample/TUI-apps/blob/main/AwkExercises
Untuk bundel, paket perintah satu baris grep, sed, awk, perl, ruby Magical one-liners seharga $5: https://learnbyexample.gumroad.com/l/oneliners/new_awk_release, dan bundel seluruh 13 ebook seharga $12: https://learnbyexample.gumroad.com/l/all-books/new_awk_release
Masukan apa pun—typo, kesalahan kode, bagian yang cocok maupun yang kurang cocok—akan sangat membantu
Diskusi sebelumnya ada di https://news.ycombinator.com/item?id=15549318 dan https://news.ycombinator.com/item?id=22758217
Mungkin saja cukup berguna untuk dibayar $5 atau $15, tetapi bisa juga tidak berbeda dari isi file perintah satu baris pribadi yang sudah saya simpan, jadi saya ragu membayar hanya untuk mengeceknya
Saya penasaran apakah versi web akan tetap gratis setelah 31 Agustus
Dulu saya pernah mencoba golf menggambar hati dengan AWK: https://gist.github.com/auselen/906a53b47a7d616b080dbef85eb8f776
99,9% penggunaan awk adalah untuk memecah baris sambil membuang spasi beruntun
Contoh:
echo "key: value" | awk '{print $1}'Akan bagus kalau ada pengganti yang lebih sederhana
Memang dibuat dengan Nim, tetapi mungkin itu bukan hambatan besar, dan alat lain di dalam
bu/juga bisa menarikcut:echo "key: value" | cut -wf 2Namun apakah itu benar-benar lebih sederhana masih bisa diperdebatkan
Setelah dicek, GNU cut tidak punya
-w, jadi itu khusus BSDPada akhirnya sepertinya lebih baik memakai awk
Keduanya adalah alternatif cut/awk dan juga mendukung pemisahan berbasis regex, tetapi seingat saya tidak menghapus spasi di awal/akhir
https://github.com/learnbyexample/regexp-cut yang saya buat sendiri adalah alat mirip
cutyang menggunakanawkuntuk menyediakan pemisahan berbasis regex, indeks negatif, dan sebagainya; berkat perilaku bawaan awk, spasi awal/akhir juga tertanganiecho "key: value" | awk '{print $2}'Dulu saya pernah menulis skrip diff2html yang dip-porting dari bash ke awk, dan tentu saja, karena alasan yang jelas, hasilnya jauh lebih cepat
Dibandingkan skrip bash, versi awk jauh lebih mudah dibaca, dan dalam semalam saya bisa mempelajari bahasanya, melakukan debugging, memahami bug, lalu memperbaikinya
Saya tidak tahu apakah itu cara awk yang idiomatis, tetapi saya merasa ini benar-benar bahasa yang bagus
https://github.com/berry-thawson/diff2html/blob/master/diff2html.sh