Redirection
perintah > berkas # tulis (timpa) stdout perintah >> berkas # tambahkan perintah 2> galat.log # stderr saja perintah > keluar.log 2>&1 # keduanya ke satu berkas perintah &> semua.log # ringkasnya (bash) perintah < masukan.txt # baca dari berkas perintah 2>/dev/null # buang pesan error
2>&1 itu penting# ✅ BENAR — stdout diarahkan ke berkas, lalu stderr mengikuti stdout perintah > berkas 2>&1 # ❌ SALAH — stderr menyalin tujuan stdout SAAT ITU (masih terminal), # baru kemudian stdout dialihkan ke berkas perintah 2>&1 > berkas
Kesalahan ini membuat pesan error tetap muncul di layar dan tidak tercatat — biasanya baru ketahuan saat Anda benar-benar membutuhkannya.
Pipe
ps aux | grep nginx | grep -v grep
cat akses.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# Menyalurkan stderr juga
perintah |& less
# tee: simpan sekaligus teruskan
perintah | tee keluaran.log | grep ERROR
grep
grep -i "error" app.log # abaikan besar-kecil huruf grep -r "TODO" src/ # rekursif grep -n "gagal" app.log # dengan nomor baris grep -v "debug" app.log # KECUALI yang cocok grep -c "error" app.log # hitung saja grep -A3 -B3 "panic" app.log # 3 baris sebelum & sesudah grep -E "error|fatal|panic" app.log grep -o "user_id=[0-9]*" app.log # hanya bagian yang cocok grep -l "koneksi" *.log # nama berkasnya saja
-A dan -B mengubah cara menelusuri logMenemukan baris error saja sering tidak cukup — Anda butuh konteks di sekitarnya untuk tahu apa yang terjadi sebelumnya. grep -B5 -A10 "panic" memberi gambaran jauh lebih utuh daripada sekadar barisnya.
awk
# Kolom ke-1 dan ke-7 dari log akses
awk '{print $1, $7}' akses.log
# Baris dengan kode status 500
awk '$9 == 500' akses.log
# Jumlahkan kolom ukuran respons
awk '{jumlah += $10} END {print jumlah/1024/1024 " MB"}' akses.log
# Hitung per kode status
awk '{hitung[$9]++} END {for (k in hitung) print k, hitung[k]}' akses.log
# Pemisah kolom kustom
awk -F: '{print $1}' /etc/passwd
awk -F',' '{print $2}' data.csv
sed
sed 's/lama/baru/' berkas # ganti kemunculan PERTAMA tiap baris sed 's/lama/baru/g' berkas # semua kemunculan sed -i.bak 's/lama/baru/g' berkas # ubah langsung, simpan cadangan .bak sed -n '10,20p' berkas # cetak baris 10-20 sed '/^#/d' konfigurasi # hapus baris komentar sed '/^$/d' berkas # hapus baris kosong
sed -i tanpa cadangan pada berkas produksiOpsi -i mengubah berkas di tempat, dan bila polanya keliru, isi aslinya sudah hilang. Selalu pakai -i.bak agar salinan tersimpan, atau jalankan tanpa -i lebih dulu untuk melihat hasilnya di layar sebelum menerapkan.
jq untuk JSON
curl -s api/pesanan | jq '.'
curl -s api/pesanan | jq '.data[] | {id, total}'
curl -s api/pesanan | jq '.data[] | select(.total > 100000)'
curl -s api/pesanan | jq -r '.data[].id' # -r: tanpa tanda kutip
kubectl get pods -o json | jq -r '.items[].metadata.name'
# Menyaring log JSON terstruktur
tail -f app.log | jq -c 'select(.level=="error") | {waktu, msg, trace_id}'
Ketika log berupa JSON, jq mengubahnya menjadi sesuatu yang bisa dikueri: saring level, ambil field tertentu, hitung per kategori. Log berupa kalimat bebas hanya bisa dihadapi dengan regex yang rapuh. Perbedaannya sangat terasa saat menelusuri insiden.
Rangkaian yang Sering Dipakai
# 10 alamat IP dengan permintaan terbanyak
awk '{print $1}' akses.log | sort | uniq -c | sort -rn | head -10
# Sebaran kode status
awk '{print $9}' akses.log | sort | uniq -c | sort -rn
# Error per jam
grep ERROR app.log | awk '{print substr($1,1,13)}' | uniq -c
# 20 berkas terbesar di bawah direktori ini
find . -type f -printf '%s %p\n' | sort -rn | head -20 | \
awk '{printf "%.1f MB %s\n", $1/1024/1024, $2}'
# Proses yang mendengarkan port beserta pemiliknya
ss -tulpn | awk 'NR>1 {print $5, $7}'