Bab 9.1.2 sudah menyinggung sekilas bahwa sed bertugas mengubah teks sebagai stream, bukan sekadar mencarinya seperti grep. Kemampuan itu jauh lebih berharga daripada terlihat sekilas: sekali kita menguasai sed, mengganti satu baris konfigurasi di puluhan server, membersihkan ribuan baris log dari data sensitif, atau menormalkan format file teks bisa selesai dalam satu baris perintah, tanpa perlu membuka editor teks sama sekali. Sysadmin memakai sed nyaris setiap hari untuk mengedit file konfigurasi lewat script otomatisasi, sementara Developer memakainya untuk memproses output build atau log aplikasi di dalam pipeline. Bab ini membahas tuntas stream editor bernama sed: cara kerjanya, sintaks substitusi teks beserta flag-flag pentingnya, edit langsung ke file (in-place), penghapusan dan penyisipan baris, pengalamatan baris, hingga studi kasus nyata mengolah file konfigurasi dan log. Regex dasar yang sudah dibahas di Bab 9.3 akan terus terpakai di sepanjang bab ini, jadi pastikan konsepnya masih segar sebelum lanjut.
10.1 Konsep dan Cara Kerja sed
Sub-bab ini membahas apa itu sed secara singkat dan bagaimana ia memproses teks di baliknya, secukupnya sebagai bekal sebelum masuk ke praktik substitusi di 10.2.
10.1.1 Apa itu Stream Editor
sed adalah singkatan dari stream editor, tool baris perintah yang mengedit teks secara non-interaktif berdasarkan instruksi yang kita berikan di awal, bukan editor teks interaktif seperti nano atau vim yang perlu dioperasikan langsung oleh manusia. Alih-alih membuka file, mengedit manual, lalu menyimpan, kita cukup memberi tahu sed "ganti kata A dengan kata B", dan seluruh file diproses otomatis dalam sekejap. Sifat non-interaktif inilah yang membuat sed sangat cocok dipakai di dalam script, karena tidak butuh campur tangan manusia di tengah proses. sed pertama kali dikembangkan di Bell Labs pada era Unix awal, dan sampai sekarang tetap jadi salah satu tool pemrosesan teks paling andal karena hampir selalu tersedia bawaan di setiap sistem mirip-Unix.
10.1.2 Anatomi Perintah sed
Bentuk umum perintah sed terdiri dari tiga bagian: nama program, script (instruksi yang mau dijalankan), dan file yang mau diproses.
sed 'script' file.txtscript sendiri biasanya terdiri dari alamat (opsional, menentukan baris mana yang kena instruksi) dan perintah (apa yang mau dilakukan pada baris itu), dengan pola umum [alamat]perintah. Konsep alamat ini dibahas lebih dalam di 10.3.3. Untuk memahami kenapa sed bekerja per baris, kita perlu tahu siklus kerjanya. Setiap kali sed memproses sebuah file, ia mengulang empat langkah berikut untuk tiap baris input:
- Baca satu baris dari input, simpan ke area kerja sementara yang disebut pattern space.
- Jalankan seluruh perintah dalam script terhadap isi pattern space itu.
- Cetak isi pattern space ke stdout, kecuali opsi
-ndipakai untuk menekan perilaku ini (dibahas di 10.2.2). - Kosongkan pattern space, lalu ulangi dari langkah 1 untuk baris berikutnya sampai seluruh input habis.
Poin paling penting dari siklus ini: sed secara default tidak pernah mengubah file aslinya. Hasil olahan hanya dicetak ke stdout, sedangkan file sumber tetap utuh, kecuali kita secara eksplisit memakai opsi -i yang dibahas di 10.3.1. Perilaku "aman secara default" ini penting diingat, karena banyak pemula mengira sed 's/a/b/' file.txt langsung mengubah file.txt, padahal perintah itu cuma menampilkan hasil olahan ke layar.
10.1.3 Memeriksa Versi sed Terpasang
Sebelum praktik, ada baiknya kita cek dulu varian sed yang terpasang di sistem, karena perilakunya sedikit berbeda antar sistem operasi, terutama soal opsi -i yang dibahas di 10.3.2.
sed --versionDi Linux dan WSL, perintah di atas biasanya menampilkan baris pertama berisi sed (GNU sed) diikuti nomor versi, karena hampir semua distro Linux dan WSL memakai GNU sed. Di macOS, sed bawaan sistem adalah BSD sed yang tidak mengenal opsi --version sama sekali, sehingga perintah di atas akan menampilkan pesan error seperti sed: illegal option -- -. Ini bukan tanda ada yang rusak, cuma bukti bahwa BSD sed memang tidak mendukung opsi panjang gaya GNU. User dan Sysadmin yang bekerja di macOS dan ingin perilaku yang konsisten dengan Linux bisa memasang GNU sed lewat Homebrew (topik instalasi Homebrew sudah disinggung di Bab 1.3), yang terpasang dengan nama perintah gsed supaya tidak bentrok dengan sed bawaan sistem.
brew install gnu-sed
gsed --version10.2 Substitusi Teks dan Flag Umum
Substitusi teks adalah alasan paling umum orang memakai sed. Sub-bab ini membahas sintaks dasar perintah s/// beserta flag-flag yang paling sering dipakai di lapangan.
10.2.1 Sintaks Dasar s///
Perintah substitusi punya bentuk s/pola/pengganti/, tiga bagian yang dipisah karakter delimiter (biasanya garis miring /). pola adalah regex yang dicari (aturan regex sama seperti grep di Bab 9.3), dan pengganti adalah teks yang menggantikannya.
echo "halo dunia" | sed 's/dunia/bash/'Perintah di atas menampilkan halo bash. Satu hal krusial yang wajib diingat: tanpa flag tambahan, s/// hanya mengganti kemunculan pertama pola dalam setiap baris, bukan seluruh kemunculan.
echo "kucing kucing kucing" | sed 's/kucing/anjing/'Hasilnya anjing kucing kucing, cuma kata pertama yang berubah. Cakupan "seluruh kemunculan" ini baru diaktifkan lewat flag g, dibahas di 10.2.2.
Delimiter garis miring pada s/// juga bisa diganti karakter lain, asalkan konsisten dipakai di ketiga posisi. Ini sangat membantu saat pola atau pengganti sendiri mengandung banyak garis miring, misalnya path file, karena tanpa delimiter alternatif kita harus meng-escape setiap garis miring dengan backslash, yang cepat bikin perintah sulit dibaca.
sed 's/\/etc\/nginx\/nginx.conf/\/etc\/nginx\/nginx.conf.bak/' daftar_path.txt
sed 's#/etc/nginx/nginx.conf#/etc/nginx/nginx.conf.bak#' daftar_path.txtKedua perintah di atas melakukan hal yang sama, tapi baris kedua jauh lebih mudah dibaca karena memakai # sebagai delimiter, sehingga garis miring di dalam path bisa ditulis apa adanya tanpa perlu di-escape. Karakter apa saja bisa dipakai sebagai delimiter selama tidak muncul di dalam pola atau pengganti itu sendiri; pilihan umum lain selain # adalah | atau ,.
10.2.2 Flag g, i, dan p
Tiga flag ini ditambahkan setelah delimiter penutup ketiga pada perintah s///, dan bisa digabung dalam satu perintah untuk mengatur cakupan serta cara substitusi bekerja.
Flag g (global) membuat sed mengganti setiap kemunculan pola dalam satu baris, bukan cuma yang pertama.
echo "kucing kucing kucing" | sed 's/kucing/anjing/g'Perintah di atas menghasilkan anjing anjing anjing. Perlu diingat bahwa "global" di sini berarti global dalam satu baris, karena sed memang otomatis memproses setiap baris di seluruh file, jadi flag g murni soal jumlah kemunculan per baris, bukan soal cakupan file. Sebagai variasi tambahan, sed juga menerima angka sebagai flag, misalnya s/pola/pengganti/2 yang hanya mengganti kemunculan kedua, atau kombinasi s/pola/pengganti/2g yang mengganti kemunculan kedua dan seterusnya. Kombinasi angka ini jarang dipakai sehari-hari, tapi berguna untuk kasus spesifik saat kita cuma ingin mengubah kemunculan tertentu, bukan semuanya.
Flag i membuat pencocokan pola menjadi case-insensitive, mengabaikan perbedaan huruf besar dan kecil, sama seperti opsi -i pada grep yang sudah dibahas di Bab 9.2.3 meski letaknya berbeda (di sed, i jadi flag setelah s///, bukan opsi baris perintah terpisah).
sed 's/error/GAGAL/gi' /var/log/aplikasi.logPerintah di atas mengganti error, Error, maupun ERROR sekaligus dengan GAGAL. Satu catatan portabilitas penting: flag i untuk s/// adalah ekstensi GNU, bukan bagian dari standar POSIX. Artinya, flag ini bekerja normal di GNU sed (Linux, WSL), tapi tidak dikenali oleh BSD sed bawaan macOS yang disinggung di 10.1.3, dan akan memunculkan error seperti bad flag in substitute command. Jika script memang perlu portable ke macOS tanpa GNU sed terpasang, alternatifnya adalah menormalkan case teks lebih dulu dengan tr '[:upper:]' '[:lower:]' seperti pola yang sudah disinggung di Bab 9.4.4, baru dicocokkan tanpa flag i.
Flag p mencetak ulang pattern space setelah substitusi berhasil, terpisah dari pencetakan otomatis di akhir siklus yang sudah dijelaskan di 10.1.2. Kalau dipakai sendirian, efeknya baris yang cocok tampil dua kali, karena tercetak sekali oleh flag p dan sekali lagi oleh siklus normal. Flag ini baru terasa gunanya saat dipadukan dengan opsi -n, yang menekan pencetakan otomatis di akhir siklus, sehingga hanya baris yang benar-benar diminta yang tampil.
sed -n 's/error/GAGAL/gp' /var/log/aplikasi.logPerintah di atas hanya menampilkan baris yang mengandung error (setelah diganti jadi GAGAL), sementara baris lain yang tidak cocok tetap diproses tapi tidak ditampilkan sama sekali. Kombinasi -n dengan p juga sering dipakai tanpa substitusi sama sekali, murni untuk menampilkan baris tertentu berdasarkan alamat baris (dibahas di 10.3.3), fungsinya mirip grep tapi dengan kontrol posisi baris yang lebih presisi.
sed -n '5,10p' /var/log/aplikasi.logPerintah di atas menampilkan baris 5 sampai 10 saja, kombinasi head dan tail (Bab 2.3) dalam satu perintah.
10.3 Edit In-Place dan Pengalamatan Baris
Sub-bab ini membahas cara mengubah file secara langsung dengan sed, cara menargetkan baris tertentu lewat pengalamatan baris, serta perintah untuk menghapus dan menyisipkan baris.
10.3.1 Opsi -i untuk Edit In-Place
Seperti disinggung di 10.1.2, sed secara default hanya mencetak hasil olahan ke stdout tanpa mengubah file sumber. Opsi -i (in-place) mengubah perilaku ini: hasil substitusi langsung ditulis kembali ke file aslinya.
sed -i 's/produksi/staging/g' konfigurasi.envPerintah di atas langsung mengubah isi konfigurasi.env, tanpa menampilkan apa pun ke layar. Karena sifatnya yang mengubah file secara permanen dan tidak bisa dibatalkan lewat sed itu sendiri, kebiasaan yang baik di lapangan adalah selalu menjalankan perintah tanpa -i lebih dulu untuk memeriksa hasilnya di layar, baru menambahkan -i setelah yakin polanya benar. GNU sed juga mendukung backup otomatis lewat suffix yang ditempel langsung setelah -i tanpa spasi.
sed -i.bak 's/produksi/staging/g' konfigurasi.envPerintah di atas menyimpan salinan file asli sebagai konfigurasi.env.bak sebelum menulis perubahan, jaring pengaman sederhana yang sangat dianjurkan dipakai Sysadmin saat mengedit file konfigurasi produksi lewat script otomatisasi. Suffix ini wajib menempel langsung tanpa spasi (-i.bak, bukan -i .bak), karena GNU sed akan salah mengartikan .bak sebagai nama file yang mau diproses jika ditulis terpisah.
10.3.2 Troubleshooting: GNU sed vs BSD sed
Perbedaan paling sering menjebak antara GNU sed dan BSD sed (bawaan macOS, disinggung di 10.1.3) ada di opsi -i ini. GNU sed menganggap suffix backup bersifat opsional, boleh dipakai -i saja tanpa backup, sedangkan BSD sed mewajibkan argumen suffix selalu ditulis eksplisit, meski kosong sekalipun.
# GNU sed (Linux, WSL), tanpa backup
sed -i 's/produksi/staging/g' konfigurasi.env
# BSD sed (macOS bawaan), argumen suffix wajib ada, kosong berarti tanpa backup
sed -i '' 's/produksi/staging/g' konfigurasi.envKalau perintah GNU-style di atas dijalankan apa adanya di macOS dengan sed bawaan, BSD sed akan menganggap 's/produksi/staging/g' sebagai suffix backup, lalu konfigurasi.env sebagai script, hasilnya justru error atau perilaku yang tidak diharapkan. Ini jebakan klasik bagi Sysadmin dan Developer yang menulis script di Linux lalu menjalankannya apa adanya di macOS. Solusi paling praktis untuk script yang perlu portable ke banyak platform sekaligus adalah memakai GNU sed lewat gsed yang sudah dipasang di 10.1.3, sehingga perilaku -i konsisten di semua platform tanpa perlu menulis percabangan kondisi khusus per sistem operasi.
10.3.3 Pengalamatan Baris
Line addressing (pengalamatan baris) menentukan baris mana saja yang kena sebuah perintah sed, ditulis sebelum perintahnya. Tanpa alamat, perintah berlaku untuk setiap baris di seluruh file.
| Bentuk Alamat | Arti | Contoh |
|---|---|---|
N | Baris nomor N | 3d menghapus baris ke-3 |
$ | Baris terakhir | $d menghapus baris terakhir |
/regex/ | Baris yang cocok dengan regex | /^#/d menghapus baris yang diawali # |
alamat1,alamat2 | Rentang baris dari alamat1 sampai alamat2 | 2,5d menghapus baris 2 sampai 5 |
alamat! | Negasi, kebalikan dari alamat | /^#/!d menghapus semua baris kecuali komentar |
Rentang baris juga bisa memakai regex di kedua sisi, berguna saat kita tidak tahu persis nomor barisnya tapi tahu pola pembuka dan penutup blok teksnya.
sed -n '/^server {/,/^}/p' nginx.confPerintah di atas menampilkan seluruh blok teks mulai dari baris yang diawali server { sampai baris yang berisi } penutup, cara praktis mengintip satu blok konfigurasi tanpa perlu membuka file konfigurasi nginx.conf secara utuh.
10.3.4 Menghapus Baris dengan d
Perintah d menghapus baris yang cocok dengan alamat di depannya dari pattern space, sehingga baris itu tidak ikut tercetak di output.
sed '/^$/d' catatan.txtPerintah di atas menghapus seluruh baris kosong dari catatan.txt, pola ^$ yang sama seperti dijelaskan di Bab 9.3.4 untuk mencocokkan baris tanpa karakter sama sekali. Kombinasi paling umum di lapangan adalah membersihkan file konfigurasi dari baris komentar sekaligus baris kosong dalam satu perintah.
sed -e '/^#/d' -e '/^$/d' /etc/ssh/sshd_configOpsi -e memungkinkan lebih dari satu script dijalankan berurutan dalam satu perintah sed, di sini menghapus baris komentar lebih dulu, baru baris kosong.
10.3.5 Menyisipkan dan Mengganti Baris
Tiga perintah a, i, dan c menambah atau mengganti baris utuh, berbeda dari s/// yang cuma mengganti sebagian teks di dalam baris.
| Perintah | Fungsi |
|---|---|
a teks | Menyisipkan teks sebagai baris baru setelah baris yang cocok dengan alamat |
i teks | Menyisipkan teks sebagai baris baru sebelum baris yang cocok dengan alamat |
c teks | Mengganti seluruh baris yang cocok dengan alamat menjadi teks |
sed '/^upstream backend {/a\ server 127.0.0.1:8080;' nginx.confPerintah di atas menyisipkan satu baris baru tepat setelah baris yang mengandung upstream backend {. Sintaks di atas memakai bentuk satu baris yang didukung GNU sed; standar POSIX aslinya mewajibkan backslash diikuti baris baru sungguhan sebelum teks yang disisipkan, bentuk yang lebih portable ke berbagai varian sed tapi juga lebih merepotkan ditulis langsung dari baris perintah.
sed '/^Listen 80$/c\
Listen 8080' httpd.confPerintah di atas mengganti seluruh baris Listen 80 menjadi Listen 8080. Bedanya dengan s///: c mengganti baris apa adanya secara utuh tanpa perlu tahu persis isi lengkapnya lebih dulu lewat regex yang rumit, cukup cocokkan alamatnya saja.
10.4 Studi Kasus: File Konfigurasi dan Log
Sub-bab penutup ini menggabungkan seluruh teknik dari 10.1 sampai 10.3 ke dalam dua skenario yang sering dihadapi Sysadmin di lapangan: mengubah directive konfigurasi dan membersihkan log dari data sensitif.
10.4.1 Mengaktifkan Directive Konfigurasi
Skenario umum saat hardening server (topik yang dibahas lebih dalam di Bab 23): memastikan sebuah directive (baris pengaturan) di file konfigurasi aktif dengan nilai tertentu, baik directive itu sedang dinonaktifkan lewat komentar # maupun sudah aktif dengan nilai lain.
sed -i.bak 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_configPola ^#\?PermitRootLogin.* mencocokkan baris yang diawali PermitRootLogin, baik didahului tanda komentar # maupun tidak, berkat \? yang berarti "karakter sebelumnya opsional" di dialek BRE (metakarakter yang sama seperti tabel BRE vs ERE di Bab 9.3.3). Baris yang cocok, apa pun isi lengkapnya setelah nama directive, langsung diganti utuh menjadi PermitRootLogin no. Opsi -i.bak memastikan file asli tersimpan sebagai cadangan sebelum diubah, langkah yang wajib dilakukan sebelum mengedit file konfigurasi krusial seperti sshd_config di server produksi, karena kesalahan pola regex pada file ini berpotensi mengunci akses SSH sama sekali.
10.4.2 Menyamarkan Data Sensitif di Log
Log aplikasi kadang tanpa sengaja mencatat data sensitif seperti password atau token di dalam URL atau parameter, risiko keamanan nyata kalau file log itu dibagikan ke tim lain untuk debugging atau diunggah ke sistem monitoring pihak ketiga. Kalau file log semacam ini bocor atau jatuh ke tangan Attacker, password dan token di dalamnya bisa langsung dipakai untuk masuk ke akun sungguhan, bukan sekadar risiko teoretis. sed bisa menyamarkan data semacam ini lewat capturing group dan backreference.
echo "GET /login?user=budi&password=rahasia123 HTTP/1.1" | sed -E 's/(password=)[^&]*/\1***/'Perintah di atas menghasilkan GET /login?user=budi&password=*** HTTP/1.1. Bagian (password=) adalah capturing group, potongan pola yang diapit tanda kurung supaya hasilnya bisa dipakai ulang di bagian pengganti lewat \1 (merujuk isi grup pertama). Pola [^&]* mencocokkan seluruh karakter setelah password= sampai ketemu karakter & atau akhir baris, alias nilai password itu sendiri, yang lalu diganti dengan *** sementara teks password= dipertahankan apa adanya lewat \1. Opsi -E di sini dipakai supaya tanda kurung ( ) langsung dikenali sebagai metakarakter grouping tanpa perlu di-escape, konsisten dengan penjelasan ERE di Bab 9.3.3.
10.4.3 Troubleshooting: BRE vs ERE di sed
sed mewarisi dialek regex yang sama persis seperti grep: BRE (Basic Regular Expression) sebagai default, ERE (Extended Regular Expression) lewat opsi -E atau -r. Kesalahan paling umum pemula adalah menulis pola bergaya ERE tanpa opsi -E, sehingga metakarakter seperti +, ?, |, dan ( ) diperlakukan sebagai karakter literal biasa, bukan metakarakter.
echo "warna: merah|biru" | sed 's/(merah|biru)/WARNA/'Perintah di atas tidak menghasilkan warna: WARNA seperti yang mungkin diharapkan. Karena dijalankan tanpa -E, tanda kurung dan garis vertikal dianggap literal, sehingga pola hanya cocok jika teks benar-benar mengandung karakter (merah|biru) apa adanya, termasuk tanda kurungnya. Perbaikannya, sesuai tabel BRE vs ERE di Bab 9.3.3, ada dua opsi: tambahkan -E, atau escape setiap metakarakter secara manual di BRE.
echo "warna: merah|biru" | sed -E 's/(merah|biru)/WARNA/'
echo "warna: merah|biru" | sed 's/\(merah\|biru\)/WARNA/'Kedua baris di atas sama-sama menghasilkan warna: WARNA. Kebiasaan yang paling aman di lapangan: begitu pola yang dibutuhkan melibatkan grouping, alternasi, atau kuantifier seperti + dan {n,m}, langsung pakai -E sejak awal, karena hasilnya jauh lebih mudah dibaca dibanding versi BRE yang penuh backslash. Setelah menguasai sed untuk mengubah teks per baris, Bab 11 melanjutkan ke awk, tool yang lebih unggul saat data yang diolah punya struktur kolom, seperti file CSV atau log yang tiap barisnya perlu dipecah jadi beberapa field bermakna.

