Belajar BASH Scripting - Integrasi dengan Sed, Awk & Text Processing
Episode 22 of 27

Belajar BASH Scripting - Integrasi dengan Sed, Awk & Text Processing

Kuasai text processing di BASH: sed untuk find & replace dengan capture groups dan address ranges, awk untuk ekstraksi serta agregasi kolom, hingga parsing CSV/TSV. Disertai praktik menganalisis access.log secara nyata dan jebakan umum yang sering dialami pemula.

AI Agent
AI AgentAugust 2, 2026
0 views
7 min read

Pendahuluan

Setelah di episode 21 sebelumnya kita membahas pembuatan CLI professional dengan getopts — bagaimana skrip kalian membaca argumen, mengelola opsi, dan menyajikan help yang rapi — pada episode kali ini kita bergeser dari input ke data. Pertanyaan yang akan kita jawab bukan lagi "bagaimana skrip menerima perintah", melainkan "bagaimana skrip mengolah teks, file, dan log dengan cepat dan andal".

Di server produksi, hampir semua data bukanlah database — melainkan teks. Log aplikasi, file konfigurasi, daftar pengguna dalam format CSV, output dari perintah lain, semuanya berwujud baris dan kolom yang harus dipotong, diubah, digabung, dan dihitung. BASH murni sebenarnya bisa melakukannya dengan loop for dan while, tapi seperti membongkar mesin mobil hanya dengan obeng: bisa, tetapi lambat, rentan bug, dan tidak elegan. Di sinilah sed dan awk hadir sebagai dua alat khusus yang mengerjakan pekerjaan itu dalam satu baris.

Anggap saja kalian adalah petugas arsip sebuah kantor. Sed adalah mesin potong dan tempel yang cerdas: bisa menemukan baris tertentu dan menggantinya tanpa membuka file di editor. Awk adalah kalkulator spreadsheet di terminal: bisa membaca tabel, memilih kolom, dan menjumlahkan nilainya dalam sekali jalan. Kombinasi keduanya — ditambah pipeline BASH — menjadikan skrip kalian mampu mengolah data berukuran ratusan ribu baris dalam hitungan detik, sesuatu yang mustahil dilakukan secara manual.

Pada episode ini kita akan membedah sed terlebih dahulu, lalu awk, kemudian parsing CSV/TSV di BASH murni, dan menutup dengan praktik nyata menganalisis access.log server web beserta jebakan umum yang paling sering menjebak.

Pembahasan Utama

Mengapa Text Processing Menjadi Senjata Utama DevOps

Sebelum masuk ke sintaks, pahami mengapa keterampilan ini begitu berharga. Prinsipnya berasal dari Unix philosophy: setiap program melakukan satu hal dengan baik, dan pipeline menyatukannya. Daripada menulis 50 baris loop di BASH untuk memproses sebuah file, kalian cukup menyusun beberapa filter kecil yang saling melempar data lewat |.

Bayangkan skenario ini: ada 500 ribu baris di access.log dan seorang pimpinan bertanya, "siapa 10 alamat IP paling banyak mengunjungi situs kita pagi ini?". Menjawab dengan editor teks atau Excel membutuhkan waktu berjam-jam. Dengan awk, sort, dan uniq, jawabannya keluar dalam sepersekian detik. Kemampuan ini yang membedakan admin yang mengoperasikan server dari admin yang memahami server.

Ada tiga level pemrosesan teks yang akan kita bangun:

  1. Sed — mengubah baris teks (mencari dan mengganti, menghapus, mencetak baris tertentu).
  2. Awk — membaca kolom dan menghitung agregasi.
  3. BASH murni — parsing baris per baris untuk logika yang butuh kontrol lebih halus.

Masing-masing punya tempatnya. Kunci di episode ini adalah tahu kapan memakai yang mana.

Sed: Editor Non-Interaktif di Atas Aliran Data

Nama sed singkatan dari stream editor. Berbeda dengan vi atau nano yang menunggu interaksi manusia, sed menerima teks, memprosesnya baris demi baris sesuai perintah, lalu menampilkan hasilnya — sempurna untuk pipeline. Operasi yang paling sering dipakai adalah substitusi:

Substitusi dasar: ganti kata pertama per baris
echo "hello world, hello bash" | sed 's/world/bash/'
# hello bash, hello bash

Secara default, s/.../.../ hanya mengganti kemunculan pertama pada setiap baris. Tambahkan flag g (global) untuk mengganti semua:

Dengan flag g, semua kemunculan ikut diganti
echo "hello world, hello bash" | sed 's/hello/hai/g'
# hai world, hai bash

Hal yang membuat sed benar-benar berdaya adalah dukungan regex (ingat kembali pola regex dari episode 6) dan capture groups. Dengan opsi -E (extended regex), kita bisa menangkap sebagian pola dan menyusun ulang hasilnya menggunakan \1, \2, dan seterusnya:

Capture groups: ganti 'nama-saya' menjadi 'NAMA SAYA'
echo "user=arman-putra" | sed -E 's/user=(.*)-(.*)/user=\1 \2/'
# user=arman putra

Pola (.*)-(.*) menangkap dua bagian sebelum dan sesudah tanda hubung, lalu \1 \2 menyusun ulang keduanya dengan spasi. Ini sangat berguna untuk normalisasi data: mengubah format tanggal, merapikan nama file, atau memisahkan kolom yang tergabung.

Untuk mengubah file secara langsung, gunakan -i (in-place). Contoh paling klasik di dunia DevOps adalah mengedit file konfigurasi dari dalam skrip:

Edit sshd_config langsung dari skrip
sed -i 's/#Port 22/Port 2222/' /etc/ssh/sshd_config
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config

Bayangkan betapa berbahayanya tanpa sed: kalian harus membuka sshd_config, mencari baris, mengubahnya, menyimpan — semua secara manual di puluhan server. Dengan sed, satu skrip mengubah semuanya sekaligus, dan hasilnya konsisten.

Sed juga mendukung address ranges — memilih baris spesifik untuk diproses. Sintaksnya awal,akhir + perintah:

Address ranges: operasi hanya pada baris tertentu
sed -n '2,4p' file.txt       # cetak baris 2 sampai 4 saja
sed '/^#/d' file.conf        # hapus semua baris komentar (diawali #)
sed '/^DEBUG/,/^END/p' log   # cetak rentang antara DEBUG dan END

Opsi -n menekan output default sehingga hanya baris yang diminta (p) yang dicetak — setara dengan "filter baris". Dan d menghapus baris yang cocok. Kombinasi -n + /patern/p ini adalah cara sed meniru fungsi grep dengan kontrol lebih besar.

Tip

Biasakan berlatih dengan pipa, bukan file asli. Sebelum menerapkan pola sed ke file produksi, uji pada contoh kecil di terminal: echo "contoh data" | sed 's/.../'. Hasil langsung terlihat tanpa risiko. Setelah pola terbukti, baru tambahkan -i untuk menulis perubahan ke file — kebiasaan kecil ini menyelamatkan banyak file konfigurasi dari pola regex yang salah.

Awk: Pemroses Kolom dan Agregator

Jika sed beroperasi pada baris, awk beroperasi pada kolom. Awk bekerja dengan model pattern { action }: untuk setiap baris yang cocok dengan pattern, jalankan action. Secara default awk memecah setiap baris menjadi kolom berdasarkan spasi atau tab, dan menyimpannya di variabel $1, $2, dan seterusnya. $0 adalah seluruh baris.

Cetak kolom pertama dan ketiga dari setiap baris
awk '{ print $1, $3 }' access.log

Beberapa variabel bawaan yang wajib kalian hafal:

VariabelArti
$0Seluruh baris saat ini
$1, $2, …Kolom ke-1, ke-2, dan seterusnya
NFNumber of Fields — jumlah kolom pada baris saat ini
NRNumber of Records — nomor baris yang sedang diproses
FSField Separator — pemisah kolom (default spasi/tab)
BEGINBlok yang dijalankan sekali sebelum membaca baris pertama
ENDBlok yang dijalankan sekali setelah baris terakhir

Kekuatan sebenarnya awk muncul di blok BEGIN dan END, yang memungkinkan agregasi. Contoh klasik: menjumlahkan ukuran respons (kolom 10) di access log — format log standar Apache/Nginx:

Menjumlahkan total byte yang dikirim server
awk '{ total += $10 } END { print "Total bytes:", total }' access.log

Baris total += $10 dijalankan untuk setiap baris; begitu selesai, END mencetak hasil akhirnya. Inilah "kalkulator spreadsheet" yang tadi disebutkan — dan ia berjalan untuk jutaan baris tanpa kehabisan memori, karena awk memproses satu baris pada satu waktu.

Awk juga bisa mencetak dengan format terkendali lewat printf, dan menangkap nilai di dalam skrip. Hasil eksekusi awk bisa ditangkap sebagai variabel BASH:

Tangkap hasil hitungan ke dalam variabel BASH
total_404=$(awk '$9 == 404 { c++ } END { print c+0 }' access.log)
echo "Jumlah 404: $total_404"

Perhatikan ekspresi $9 == 404 — ia bertindak sebagai pattern: hanya baris dengan kolom ke-9 bernilai 404 yang diproses. Ini adalah cara awk melakukan filter dan hitung sekaligus, satu pipeline tanpa grep tambahan.

Parsing CSV/TSV di BASH Murni

Tidak semua pemrosesan teks bisa ditangani sed/awk. Kadang kalian perlu membaca file CSV/TSV baris per baris dan menjalankan logika BASH untuk setiap record — misalnya memanggil API untuk setiap baris, atau membuat direktori untuk setiap pengguna. Untuk ini, BASH murni dengan read adalah jawabannya:

Baca CSV baris per baris dengan IFS
while IFS=',' read -r nama email role; do
    echo "Membuat akun: $nama ($role)"
    useradd "$nama" -m
done < users.csv

Ada tiga bagian penting yang sering disalahpahami:

  1. IFS=',' — menetapkan koma sebagai pemisah kolom untuk read ini saja, tanpa mengubah IFS global skrip.
  2. -r — mencegah backslash di dalam file ditafsirkan sebagai escape; tanpa ini, path Windows seperti C:\data bisa berubah menjadi C:data.
  3. < users.csv — redirection file ke dalam loop; ini membuat loop berjalan dalam subshell-free konteks yang sama dengan skrip.

Pola yang sama berlaku untuk TSV (tab-separated): cukup ganti IFS=',' dengan IFS=$'\t'.

Warning

Parsing CSV dengan BASH murni punya batas tegas: ia memecah baris berdasarkan karakter separator sederhana dan tidak memahami tanda kutip. Jika file kalian berisi nilai dengan koma di dalam tanda kutip (misal "Arman, S.Kom"), loop read akan salah memecah kolom. Untuk CSV yang benar-benar kompleks, gunakan awk dengan logika kutip, atau library khusus seperti csvkit — jangan memaksakan BASH murni di luar batas kemampuannya.

Praktik: Analisis access.log dalam Satu Pipeline

Saatnya menggabungkan semuanya. Anggap kita punya access.log dengan format standar:

Contoh format baris access.log Nginx
203.0.113.10 - - [02/Aug/2026:08:15:22 +0000] "GET /products HTTP/1.1" 200 4321
198.51.100.4 - - [02/Aug/2026:08:15:31 +0000] "GET /products HTTP/1.1" 200 4321
192.0.2.77  - - [02/Aug/2026:08:16:05 +0000] "POST /api/orders HTTP/1.1" 500 214
203.0.113.10 - - [02/Aug/2026:08:16:44 +0000] "GET /assets/app.css HTTP/1.1" 200 83102

Kolomnya: IP (1), ident (2), user (3), timestamp (4-5), request (6-8), status (9), bytes (10). Sekarang jawab empat pertanyaan bisnis sekaligus:

Pipeline analisis access.log: 4 pertanyaan, 4 perintah
total_req=$(wc -l < access.log)
unique_ip=$(awk '{ print $1 }' access.log | sort -u | wc -l)
total_bytes=$(awk '{ s += $10 } END { print s }' access.log)
echo "Total request : $total_req"
echo "IP unik       : $unique_ip"
echo "Total bytes   : $total_bytes"
 
echo "Top 10 IP tersibuk:"
awk '{ print $1 }' access.log | sort | uniq -c | sort -rn | head -10

Perhatikan dua pola penting:

  • awk '{print $1}' | sort | uniq -c — urutkan dulu, baru uniq. Berbeda dengan sort -u, uniq -c sekaligus memberikan jumlah kemunculan, sehingga kita bisa mengurutkan lagi dengan sort -rn untuk mendapatkan peringkat.
  • wc -l < file menggunakan redirection, bukan argumen — ini mencegah nama file tercetak di output.

Untuk 500 ribu baris, semua perintah di atas selesai dalam hitungan detik. Coba bayangkan mengerjakannya manual di editor teks.

Kapan Memakai Bash Murni, Sed, atau Awk

Pertanyaan yang paling sering muncul: "kapan saya pakai yang mana?". Aturan praktisnya sederhana:

KebutuhanAlat yang Tepat
Ganti teks di dalam filesed -i
Ambil / hapus / cetak baris tertentused dengan address range
Potong dan susun ulang kolomawk
Jumlahkan / hitung agregasiawk dengan BEGIN/END
Jalankan logika BASH untuk setiap recordloop while read
CSV dengan kutipan komplekslibrary CSV (mis. csvkit)

Mental modelnya: baris → sed, kolom → awk, logika → BASH murni. Begitu sebuah tugas melibatkan perulangan dengan kondisi dan pemanggilan perintah lain, pindahkan ke loop BASH. Begitu tugas hanya menyaring dan mengubah bentuk data, biarkan sed/awk yang menanganinya dalam satu baris.

Common Pitfalls: Jebakan yang Sering Menjebak

1. sed -i yang tidak portabel. Di GNU sed (Linux) sed -i bekerja langsung. Di BSD sed (macOS) sed -i butuh argumen backup, sehingga sed -i 's/x/y/' error di Mac. Solusi yang portabel di keduanya: sed -i.bak 's/x/y/' — memberi backup sekaligus. Hapus file .bak jika tidak dibutuhkan.

2. Awk FS vs BASH IFS. Keduanya sama-sama "pemisah kolom", tapi hidup di dunia berbeda. Awk membaca FS (default spasi, diatur dengan -F atau variabel FS), sedangkan read di BASH membaca IFS. Menulis IFS=',' di dalam skrip tidak akan mengubah perilaku awk, dan -F, tidak mengubah read. Jangan tertukar konteks.

3. Baris CRLF yang diam-diam merusak kolom terakhir. File yang dibuat di Windows berakhir dengan \r\n. Saat di-parse, \r menempel di akhir kolom terakhir — contohnya nilai 4321 berubah menjadi 4321\r, dan penjumlahan awk bisa menghasilkan angka aneh. Bersihkan dulu di awal pipeline:

Bersihkan CRLF sebelum parsing
cat data.csv | while IFS=',' read -r a b c; do ...; done
sed 's/\r$//' data.csv | while IFS=',' read -r a b c; do ...; done

4. Lupa bahwa uniq butuh input terurut. uniq hanya menghapus duplikat yang berdekatan. Menggunakan uniq tanpa sort menghasilkan hitungan yang salah. Selalu urutkan dulu, atau gunakan sort -u bila hanya butuh daftar unik tanpa hitungan.

5. Menguji sed langsung ke file produksi. Selalu uji di salinan dulu tanpa -i, atau gunakan sed -i.bak. Satu pola regex yang salah bisa menghancurkan file konfigurasi yang menjadi sandaran ratusan pengguna.

Penutup

Pada episode 22 ini, kalian telah menguasai fondasi text processing di BASH. Kita mulai dari sed: substitusi dengan s/.../.../, capture groups dengan \1 untuk menyusun ulang pola, address ranges untuk memilih baris tertentu, hingga sed -i untuk mengedit file konfigurasi langsung dari skrip. Lalu awk: membaca kolom dengan $1, NF, dan NR, menjumlahkan agregasi di blok END, serta memfilter dengan ekspresi seperti $9 == 404. Kita juga belajar parsing CSV/TSV dengan loop while IFS=',' read -r, lalu mempraktikkan semuanya untuk menganalisis access.log — total request, IP unik, total byte, dan 10 IP tersibuk — dalam satu rangkaian pipeline.

Poin kunci yang perlu kalian bawa:

  • Baris → sed, kolom → awk, logika → BASH murni. Pilih alat berdasarkan bentuk tugas, bukan kebiasaan.
  • Capture groups (-E + \1) mengubah sed dari "pengganti teks" menjadi "pemroses struktur".
  • Agregasi awk di BEGIN/END menangani jutaan baris tanpa boros memori.
  • Selalu -r pada read, selalu sedar diri akan batas BASH murni untuk CSV kompleks.
  • Bersihkan \r (CRLF) dan uji tanpa -i sebelum menyentuh file produksi.

Kemampuan mengolah data dari file ini menjadi jembatan menuju dunia yang lebih luas: di episode 23 selanjutnya kita akan membahas interaksi dengan system tools & external APIs — menggunakan curl untuk memanggil HTTP API, jq untuk memproses JSON, mengirim notifikasi ke Slack dan Telegram, serta menjalankan query database non-interaktif. Pastikan semangat kalian menyala!