grep, sed, dan awk: contoh pengolahan teks di terminal Linux
grep mencari baris berdasarkan pola (grep -rn error /var/log), sed mengubah teks dalam aliran atau berkas (sed -i 's/old/new/g' file), dan awk bekerja dengan kolom serta menghitung (awk '{print $1}' access.log). Bersama dalam pipeline, ketiganya menggantikan skrip: grep menyaring baris, sed memperbaiki teks, awk memotong field dan mengagregasi.
grep, sed, dan awk adalah tiga utilitas klasik Linux untuk mengolah teks. grep mencari baris yang cocok dengan pola, sed mengganti dan menghapus teks dalam aliran tanpa membuka editor, sedangkan awk memecah baris menjadi kolom dan bisa menghitung. Di bawah ini adalah contoh grep sed awk yang benar-benar dibutuhkan saat menganalisis log, konfigurasi, dan keluaran perintah, beserta kesalahan yang paling sering terjadi.
Kapan menggunakan yang mana
Ketiga alat ini membaca teks baris demi baris dan menulis hasilnya ke keluaran standar, sehingga mudah dirangkai dengan |. Perbedaannya terletak pada tugas yang paling cocok untuk masing-masing.
| Tugas | Alat | Contoh |
|---|---|---|
| Mencari baris dengan teks tertentu | grep | grep ERROR app.log |
| Mengganti teks | sed | sed 's/http:/https:/g' file |
| Menghapus atau menampilkan baris berdasarkan nomor | sed | sed -n '10,20p' file |
| Mengambil satu kolom | awk | awk '{print $1}' access.log |
| Menghitung jumlah, rata-rata, atau pengelompokan | awk | awk '{s+=$10} END {print s}' |
Aturan sederhananya: jika hanya perlu menyaring, gunakan grep; jika perlu mengubah teks, gunakan sed; jika teks memiliki kolom atau perlu aritmetika, gunakan awk.
grep: mencari baris berdasarkan pola
Contoh dasar grep
# Baris yang berisi kata error dalam berkas
grep error /var/log/syslog
# Tanpa membedakan huruf besar-kecil: Error, ERROR, error
grep -i error app.log
# Dengan nomor baris
grep -n "Connection refused" app.log
# Rekursif dalam direktori, dengan nama berkas
grep -rn "DB_HOST" /etc/myapp/
# Hanya nama berkas yang memiliki kecocokan
grep -rl "TODO" src/
# Dibalik: semua KECUALI komentar dan baris kosong
grep -v -e '^#' -e '^$' /etc/ssh/sshd_config
# Menghitung jumlah baris yang cocok
grep -c " 500 " access.log
Flag -w mencari kata secara utuh: grep -w log tidak akan menemukan login. Flag -F mematikan regular expression dan mencari string secara harfiah, berguna jika pola mengandung titik, tanda kurung, atau bintang.
Konteks di sekitar baris yang cocok
Sebuah error di log jarang bisa dipahami dari satu baris saja. Anda membutuhkan stack trace atau permintaan yang memicunya. Untuk itu tersedia flag konteks:
# 3 baris setelah kecocokan (After)
grep -A 3 "Traceback" app.log
# 2 baris sebelum (Before)
grep -B 2 "OOM" /var/log/kern.log
# 5 baris di kedua sisi (Context)
grep -C 5 "segfault" /var/log/syslog
Grep memisahkan kelompok kecocokan dengan baris --, sehingga keluarannya mudah dibaca.
grep dan regular expression
Secara default grep memahami basic regular expression (BRE). Dengan flag -E aktif extended regular expression (ERE), di mana +, ?, |, dan tanda kurung bekerja tanpa garis miring terbalik.
| Konstruksi | Arti | Contoh |
|---|---|---|
^ | awal baris | grep '^root' /etc/passwd |
$ | akhir baris | grep 'bash$' /etc/passwd |
. | karakter apa pun | grep 'h.t' |
* | 0 atau lebih pengulangan | grep 'ab*c' |
+ (ERE) | 1 atau lebih | grep -E '[0-9]+' |
| (ERE) | atau | grep -E 'error|warn' |
[...] | satu karakter dari himpunan | grep '[Ee]rror' |
# Baris dengan error atau peringatan
grep -E "ERROR|WARN" app.log
# Hanya alamat IP dari log, satu per baris (-o — cetak hanya bagian yang cocok)
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log
grep -P: mengambil nilai di antara potongan yang diketahui
GNU grep memiliki flag -P — regular expression gaya Perl. Dengan flag ini tersedia \K («lupakan semua yang cocok sampai titik ini») dan lookahead, sehingga Anda bisa mengambil hanya nilainya:
$ echo 'user_id=4821 status=ok' | grep -oP 'user_id=\K[0-9]+'
4821
$ grep -oP '"version":\s*"\K[^"]+' package.json
2.4.1
Flag -P tidak tersedia di semua build grep (misalnya BSD grep di macOS tidak memilikinya), jadi untuk skrip yang harus portabel sebaiknya gunakan sed atau awk.
grep -q dalam kondisi skrip
grep -q tidak mencetak apa pun dan hanya mengembalikan kode keluar: 0 — ditemukan, 1 — tidak ditemukan. Dengan begitu pengecekan bisa langsung ditulis di dalam if:
if grep -q "^PermitRootLogin no" /etc/ssh/sshd_config; then
echo "login root sudah dinonaktifkan"
fi
Cara ini lebih singkat daripada menyimpan keluaran ke variabel lalu memeriksa apakah variabel itu kosong, dan grep berhenti pada kecocokan pertama.
sed: mengganti dan menghapus teks
Penggantian: perintah s
Perintah utama sed adalah s/pola/pengganti/flag. Tanpa flag g, hanya kecocokan pertama di setiap baris yang diganti.
# Menampilkan teks hasil penggantian (berkas tidak berubah)
sed 's/foo/bar/' file.txt
# Mengganti semua kemunculan dalam baris
sed 's/foo/bar/g' file.txt
# Tanpa membedakan huruf besar-kecil (GNU sed)
sed 's/error/ERROR/gI' app.log
# Pembatas lain, jika teks mengandung garis miring
sed 's|/var/www|/srv/www|g' nginx.conf
sed -i: penggantian langsung di dalam berkas
Flag -i menulis hasilnya kembali ke berkas. Agar berkas asli tidak hilang, tentukan sufiks cadangan:
# Membuat config.ini.bak dan mengubah config.ini
sed -i.bak 's/^debug=true/debug=false/' config.ini
# Penggantian di semua .conf dalam direktori
find /etc/myapp -name "*.conf" -exec sed -i 's/old-host/new-host/g' {} +
Sebelum melakukan perubahan massal, jalankan perintah tanpa -i dan periksa keluarannya. Di macOS (BSD sed), -i memerlukan argumen wajib: sed -i '' 's/a/b/' file.
Bekerja dengan baris berdasarkan nomor dan pola
# Menampilkan baris 10–20 (-n mematikan pencetakan otomatis, p — cetak)
sed -n '10,20p' file.txt
# Menghapus baris 5
sed '5d' file.txt
# Menghapus baris terakhir
sed '$d' file.txt
# Menghapus baris kosong dan komentar
sed -e '/^$/d' -e '/^#/d' nginx.conf
# Mengganti hanya di baris yang berisi "listen"
sed '/listen/s/80/8080/' nginx.conf
# Menyisipkan baris setelah kecocokan (GNU sed)
sed '/^\[mysqld\]/a max_connections = 500' my.cnf
Referensi balik dan &
Bagian pola yang berada dalam tanda kurung dapat dimasukkan ke pengganti dengan \1, \2, dan karakter & berarti seluruh teks yang cocok.
# Menukar nama depan dan nama belakang (ERE dengan -E)
$ echo "Иванов Пётр" | sed -E 's/(\S+) (\S+)/\2 \1/'
Пётр Иванов
# Membungkus semua angka dengan kurung siku
$ echo "port 8080, timeout 30" | sed -E 's/[0-9]+/[&]/g'
port [8080], timeout [30]
# Mengubah tanggal 2026-10-14 menjadi 14.10.2026
$ echo 2026-10-14 | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/'
14.10.2026
awk: kolom, kondisi, dan penghitungan
Menampilkan kolom yang dibutuhkan
awk memecah setiap baris menjadi field berdasarkan spasi dan tab: $1 — field pertama, $2 — field kedua, $NF — field terakhir, $0 — seluruh baris.
# Alamat IP dari log nginx (kolom pertama)
awk '{print $1}' /var/log/nginx/access.log
# Nama pengguna dan shell dari /etc/passwd (pemisah — titik dua)
awk -F: '{print $1, $7}' /etc/passwd
# Kolom terakhir
df -h | awk '{print $NF}'
# Pemisah sendiri pada keluaran
awk -F: -v OFS=';' '{print $1, $3}' /etc/passwd
Kondisi: hanya mencetak baris yang dibutuhkan
Sebelum blok dengan kurung kurawal, Anda bisa menulis kondisi — awk hanya menjalankan aksi untuk baris yang sesuai.
# Pengguna dengan UID 1000 ke atas (pengguna biasa, bukan sistem)
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
# Permintaan dengan kode respons 500 ke atas (field ke-9 pada format combined)
awk '$9 >= 500' access.log
# Baris di mana kolom ke-6 cocok dengan regex
awk '$6 ~ /POST/' access.log
# Berkas lebih besar dari 100 MB dari keluaran ls -l
ls -l | awk '$5 > 100*1024*1024 {print $9}'
BEGIN, END, dan NR: awk sebagai program kecil
Blok BEGIN dijalankan sebelum membaca baris pertama, END — setelah baris terakhir. NR menyimpan nomor baris saat ini, dan di blok END berisi jumlah seluruh baris.
# Jumlah ukuran respons (field ke-10) dalam megabyte
awk '{sum += $10} END {printf "%.1f MB\n", sum/1024/1024}' access.log
# Rata-rata waktu respons dari kolom terakhir
awk '{s += $NF} END {if (NR) print s/NR}' timings.log
# Melewati baris header CSV
awk -F, 'NR > 1 {print $2}' users.csv
# Menghitung permintaan per IP: array asosiatif
awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' access.log | sort -rn | head
Contoh terakhir adalah resep klasik analisis log: array count dengan kunci IP menggantikan rangkaian sort | uniq -c dan mudah dikembangkan, misalnya menjadi total trafik untuk setiap alamat.
Pipeline: grep, sed, dan awk bersama
Kekuatan sebenarnya ada pada kombinasi. Setiap alat mengerjakan bagiannya, dan | meneruskan hasilnya.
10 IP teratas dengan error 5xx
grep ' 50[0-9] ' /var/log/nginx/access.log \
| awk '{print $1}' \
| sort | uniq -c | sort -rn | head -10
412 203.0.113.45
118 198.51.100.7
36 192.0.2.19
Di sini grep secara kasar menyaring baris, awk memotong field, dan sort | uniq -c menghitung pengulangan. Hal yang sama bisa ditulis dengan satu awk: awk '$9 ~ /^5/ {c[$1]++} END {for (i in c) print c[i], i}' access.log | sort -rn | head — cara ini lebih akurat, karena yang diperiksa adalah kolom kode respons.
URL mana yang paling sering dibuka
awk '{print $7}' access.log | sed 's/?.*//' | sort | uniq -c | sort -rn | head
sed di sini memotong bagian query string, sehingga /search?q=a dan /search?q=b dihitung sebagai satu halaman.
Nilai dari konfigurasi tanpa komentar
grep -v '^\s*#' /etc/myapp/app.env | grep '=' | awk -F= '{print $1}'
Error pada jam tertentu
grep '14/Oct/2026:03:' access.log | awk '$9 >= 500 {print $4, $7, $9}'
Kesalahan yang sering terjadi
- Tanda kutip ganda, bukan tunggal, untuk awk. Pada
awk "{print $1}"shell akan mengganti$1dengan variabelnya sendiri sebelum awk dijalankan. Tulis program awk dan ekspresi sed dengan tanda kutip tunggal. - Lupa
gpada sed. Tanpa flag ini hanya kecocokan pertama dalam baris yang diganti, sisanya tetap. sed -itanpa pemeriksaan. Regex yang keliru akan diam-diam merusak berkas. Jalankan dulu tanpa-iatau gunakan-i.bak.+dan|tidak berfungsi di grep. Itu sintaks extended: gunakangrep -E(ataused -E).- Titik di dalam pola.
grep 192.168.1.1juga akan menemukan192x168y1z1, karena titik berarti «karakter apa pun». Gunakangrep -Fatau escape dengan\.. - Spasi di dalam kolom. Jika field bisa berisi spasi (CSV, path), tentukan pemisah secara eksplisit:
awk -F,atauawk -F'\t'. - cat yang tidak perlu.
cat file | grep xtetap berfungsi, tetapigrep x filelebih pendek dan tidak membuat proses tambahan.
Alternatif untuk grep, sed, dan awk
Untuk JSON, alat-alat ini kurang cocok: strukturnya lebih baik diurai dengan jq (jq '.items[] | select(.status=="active") | .name'), dan YAML dengan yq. Untuk pencarian rekursif yang cepat di proyek besar, sering dipakai ripgrep (perintah rg), yang secara default mengikuti .gitignore. Jika lebih nyaman dengan sintaks Perl, perl -pe 's/a/b/g' dan perl -lane 'print $F[0]' menggantikan sed dan awk dalam satu baris. Namun grep, sed, dan awk hampir selalu tersedia di server tanpa instalasi tambahan, sehingga sebaiknya Anda menguasainya terlebih dahulu.
Kesimpulan
grep mencari baris, sed mengubahnya, dan awk bekerja dengan kolom serta menghitung. Ingat kumpulan dasarnya: grep -rniE dan -A/-B/-C, sed 's/.../.../g' dengan -i.bak dan -n 'Np', awk -F dengan $1, $NF, kondisi, dan blok END. Dari potongan-potongan inilah hampir semua analisis log dibangun. Contoh grep sed awk ini, bersama find, jq, dan curl, dibahas secara praktis dalam pelajaran kursus Linux tentang pengolahan teks di terminal.
Pertanyaan umum
Apa perbedaan grep dan egrep?
egrep adalah alias usang untuk grep -E (extended regular expression). Versi GNU grep yang modern menampilkan peringatan saat egrep dipanggil, jadi gunakan grep -E.
Bagaimana cara mencari teks di semua berkas dalam direktori di Linux?
Gunakan grep -rn "teks" /path: -r mencari secara rekursif, -n menampilkan nomor baris. Untuk membatasi jenis berkas, tambahkan --include="*.php".
Bagaimana cara mengganti teks di banyak berkas sekaligus?
Gabungkan pencarian dan sed: grep -rl "old" . | xargs sed -i 's/old/new/g'. Sebelumnya, sebaiknya buat commit atau cadangan.
Bagaimana cara mencetak beberapa kolom di awk dipisahkan tab?
Atur pemisah keluaran: awk -v OFS='\t' '{print $1, $3}' file. Tanpa OFS, field dipisahkan dengan spasi.
Bagaimana cara menghapus spasi di akhir baris dengan sed?
Perintah sed -i 's/[[:space:]]*$//' file menghapus spasi dan tab di akhir setiap baris dalam berkas.
Topik ini dibahas mendalam dengan praktik di kursus “Linux: с нуля до уверенного администрирования”.
Ke kursus