sed Kullanımı: Akış Editörü ile Metin Dönüştürme

Terminal ekranına bakıp “şu dosyada tüm şu metni bununla değiştirmeliyim ama 500 satır var” diye düşündüğünüzde aklınıza ilk gelen araç muhtemelen sed oluyor. Stream Editor, yani akış editörü olarak bilinen sed, Unix dünyasının en köklü ve en güçlü metin işleme araçlarından biri. 1970’lerde Bell Labs’ta geliştirilen bu araç, onlarca yıldır sysadmin’lerin ve geliştiricilerin vazgeçilmezi olmaya devam ediyor. Tek satır komutla binlerce dosyayı dönüştürmek, log dosyalarını temizlemek, konfigürasyon dosyalarında toplu değişiklik yapmak, bunların hepsi sed ile mümkün. Bu yazıda sed’i temelinden ileri seviye kullanımına kadar ele alacağız, gerçek dünya senaryolarıyla pekiştireceğiz.

sed Nedir ve Nasıl Çalışır?

sed, dosyaları satır satır okuyarak her satıra belirttiğiniz komutları uygulayan bir akış editörüdür. Önemli bir nokta şu: sed varsayılan olarak orijinal dosyayı değiştirmez, çıktıyı standart çıktıya (stdout) yazar. Bu davranış aslında çok akıllıca çünkü önce ne olacağını görüp sonra değişikliği kalıcı hale getirebiliyorsunuz.

sed’in çalışma mantığı şöyle işliyor:

  • Dosyadan bir satır okur ve bunu “pattern space” adı verilen geçici belleğe alır
  • Belirttiğiniz komutları bu satıra uygular
  • Sonucu stdout’a yazar
  • Sonraki satıra geçer, bu döngü dosya bitene kadar devam eder

Temel sözdizimi oldukça basit:

sed [seçenekler] 'komut' dosya

Birden fazla komut uygulamak için:

sed [seçenekler] -e 'komut1' -e 'komut2' dosya

Ya da komutları bir dosyaya yazıp:

sed -f komut_dosyasi.sed dosya

Temel Seçenekler

sed’in en sık kullanılan seçeneklerini şöyle sıralayabiliriz:

-n: Varsayılan çıktıyı bastırır, yalnızca açıkça yazdırılması istenen satırları gösterir

-i: Dosyayı doğrudan düzenler (in-place), orijinal dosyayı değiştirir

-i.bak: Dosyayı düzenler fakat önce .bak uzantısıyla yedek alır

-e: Birden fazla komut belirtmek için kullanılır

-f: Komutları bir dosyadan okur

-r veya -E: Genişletilmiş regular expression (ERE) kullanımını etkinleştirir

-s: Birden fazla dosyayı bağımsız stream olarak işler

Substitution (Değiştirme) Komutu: s

sed’in en çok kullanılan komutu tartışmasız s komutudur. Metin değiştirme işlemlerinin tamamını bu komutla yapıyorsunuz.

Temel syntax:

sed 's/aranan_metin/yeni_metin/flags' dosya

En basit örnek, bir dosyada “hata” kelimesini “error” ile değiştirmek:

sed 's/hata/error/' log.txt

Bu komut her satırda yalnızca ilk eşleşmeyi değiştirir. Satırdaki tüm eşleşmeleri değiştirmek için g (global) flag kullanıyorsunuz:

sed 's/hata/error/g' log.txt

Büyük/küçük harf duyarsız arama için I flag:

sed 's/hata/error/gI' log.txt

Eşleşmeyi yalnızca belirli bir oluşumda değiştirmek için sayı kullanabilirsiniz. Mesela satırdaki 2. eşleşmeyi değiştir:

sed 's/hata/error/2' log.txt

Sınırlayıcı Karakteri Değiştirmek

Eğer aradığınız metin / karakteri içeriyorsa (örneğin dosya yolları), her /‘yi escape etmek zorunda kalırsınız. Bu hem zahmetli hem de okunaksız bir kod üretir. Bunun yerine farklı bir sınırlayıcı karakter kullanabilirsiniz:

# Bunu yazmak zorunda değilsiniz:
sed 's//etc/nginx/nginx.conf//etc/nginx/nginx.conf.bak/' dosya

# Bunun yerine | veya # kullanın:
sed 's|/etc/nginx/nginx.conf|/etc/nginx/nginx.conf.bak|' dosya
sed 's#/etc/nginx/nginx.conf#/etc/nginx/nginx.conf.bak#' dosya

Gerçek Dünya Senaryosu 1: Nginx Konfigürasyonunda Toplu Değişiklik

Diyelim ki production ortamında 50 farklı Nginx virtual host konfigürasyon dosyanız var ve eski IP adresini yeni IP adresiyle değiştirmeniz gerekiyor. Bunları tek tek açıp düzenlemek yerine:

# Önce test edelim, dosyaları değiştirme:
sed 's/192.168.1.100/192.168.2.100/g' /etc/nginx/sites-available/example.com

# Sonuç beklediğimiz gibiyse tüm dosyalara uygulayalım:
sed -i.bak 's/192.168.1.100/192.168.2.100/g' /etc/nginx/sites-available/*

# Yedek dosyaları kontrol et:
ls /etc/nginx/sites-available/*.bak

-i.bak seçeneğini her zaman tercih edin. Bir şeyler yanlış gittiğinde .bak dosyalarına geri dönebilirsiniz. Bu küçük alışkanlık sizi büyük felaketlerden kurtarır.

Adres Belirtme: Hangi Satırlara Uygulanacak?

sed komutlarını tüm dosyaya değil, belirli satırlara da uygulayabilirsiniz. Buna “adres belirtme” deniyor.

Satır numarasıyla:

# Sadece 5. satırda değiştir:
sed '5s/eski/yeni/' dosya

# 3. satırdan 7. satıra kadar değiştir:
sed '3,7s/eski/yeni/g' dosya

# 5. satırdan dosya sonuna kadar:
sed '5,$s/eski/yeni/g' dosya

Pattern eşleşmesiyle:

# "server" kelimesini içeren satırlarda değişiklik yap:
sed '/server/s/80/8080/g' nginx.conf

# "START" ile "END" arasındaki satırlarda değişiklik yap:
sed '/START/,/END/s/eski/yeni/g' dosya

Negasyon (! operatörü):

# "yorum" içeren satırlar HARİÇ değişiklik yap:
sed '/yorum/!s/eski/yeni/g' dosya

Satır Silme, Ekleme ve Yazdırma

sed yalnızca metin değiştirmekle sınırlı değil. Satır silmek, eklemek ve yazdırmak için de kullanılıyor.

d komutu – satır silme:

# Boş satırları sil:
sed '/^$/d' dosya.txt

# Yorum satırlarını sil (# ile başlayanlar):
sed '/^#/d' dosya.conf

# Sadece boşluk içeren satırları da temizle:
sed '/^[[:space:]]*$/d' dosya.txt

# 3. satırı sil:
sed '3d' dosya.txt

# 5. satırdan 10. satıra kadar sil:
sed '5,10d' dosya.txt

p komutu – satır yazdırma (-n ile birlikte):

# Sadece "ERROR" içeren satırları göster:
sed -n '/ERROR/p' uygulama.log

# 10. ve 20. satırlar arasını göster:
sed -n '10,20p' dosya.txt

# İlk 5 satırı göster (head alternatifi):
sed -n '1,5p' dosya.txt

a komutu – satır sonrasına ekleme:

# "server_name" içeren satırın SONRASINA yeni satır ekle:
sed '/server_name/a    add_header X-Frame-Options "SAMEORIGIN";' nginx.conf

i komutu – satır öncesine ekleme:

# Dosyanın başına (1. satır öncesine) yorum ekle:
sed '1i# Bu dosya otomatik üretilmiştir. Elle düzenlemeyin.' config.conf

c komutu – satırı tamamen değiştirme:

# "MaxClients" ile başlayan satırı tamamen yenisiyle değiştir:
sed '/^MaxClients/cMaxClients 150' httpd.conf

Gerçek Dünya Senaryosu 2: Log Dosyası Analizi ve Temizleme

Production log dosyalarında çalışmak sysadmin’lerin günlük rutini. sed bu iş için biçilmiş kaftan:

# Sadece ERROR ve WARNING satırlarını filtrele:
sed -n '/ERROR|WARNING/p' uygulama.log > kritik_hatalar.log

# IP adreslerini anonim hale getir (son okteti maskele):
sed 's/([0-9]{1,3}.){3}[0-9]{1,3}/IP_GIZLENDI/g' access.log

# Tarihi standart formata dönüştür (DD/MM/YYYY -> YYYY-MM-DD):
sed 's|([0-9]{2})/([0-9]{2})/([0-9]{4})|3-2-1|g' access.log

# Log rotasyonu sonrası gzip'li dosyaları da işle:
zcat /var/log/nginx/access.log.gz | sed -n '/2024-01-15/p' > bugun.log

Regular Expression ile Güçlü Eşleşmeler

sed, regular expression desteğiyle çok daha güçlü hale geliyor. Temel regex karakterleri:

  • .: Herhangi bir karakter
  • *: Önceki karakterin sıfır veya daha fazla tekrarı
  • ^: Satır başı
  • $: Satır sonu
  • [abc]: a, b veya c karakterlerinden biri
  • [^abc]: a, b veya c dışındaki karakterler
  • +: Bir veya daha fazla tekrar (extended regex’te +)
  • {n,m}: n ile m arasında tekrar

Backreference (geri referans) kullanımı:

Eşleşen grupları (...) ile yakalayıp 1, 2 gibi referanslarla kullanabilirsiniz:

# Kelime sıralarını değiştir: "ad soyad" -> "soyad, ad"
sed 's/([A-Za-z]+) ([A-Za-z]+)/2, 1/g' isimler.txt

# HTML tag'larını temizle:
sed 's/<[^>]*>//g' sayfa.html

# Çift boşlukları tek boşluğa indir:
sed 's/  */ /g' dosya.txt

# Satır başı ve sonundaki boşlukları temizle (trim):
sed 's/^[[:space:]]*//;s/[[:space:]]*$//' dosya.txt

Çoklu Komut Kullanımı

Tek bir sed çağrısında birden fazla işlem yapabilirsiniz. Bu performans açısından önemli, özellikle büyük dosyalarda:

# Hem yorum satırlarını sil hem de boş satırları temizle:
sed -e '/^#/d' -e '/^$/d' config.conf

# Noktalı virgülle de ayırabilirsiniz:
sed '/^#/d; /^$/d' config.conf

# Daha karmaşık örnek:
sed -e 's/localhost/production-server.example.com/g' 
    -e 's/3306/5432/g' 
    -e '/^#/d' 
    -e '/^$/d' 
    database.conf > production_database.conf

Gerçek Dünya Senaryosu 3: Toplu Dosya Dönüştürme

Bir proje migration senaryosu düşünün. Eski framework’ten yeni framework’e geçiyorsunuz ve yüzlerce PHP dosyasında namespace değişikliği yapmanız gerekiyor:

# Tek dosya test:
sed 's/use OldFramework\/use NewFramework\/g' src/Controller/UserController.php

# Tüm PHP dosyalarına uygula:
find /var/www/proje -name "*.php" -exec sed -i.bak 
    's/use OldFramework\/use NewFramework\/g' {} ;

# Değişiklikleri kontrol et:
find /var/www/proje -name "*.php" | xargs grep -l "NewFramework" | wc -l

# Her şey yolundaysa yedekleri temizle:
find /var/www/proje -name "*.bak" -delete

-i Seçeneğinin macOS ve Linux Farkı

Önemli bir not: macOS’ta BSD sed kullanılır ve -i seçeneği Linux’taki GNU sed’den farklı davranır. macOS’ta -i seçeneği mutlaka bir uzantı argümanı ister:

# Linux (GNU sed):
sed -i 's/eski/yeni/g' dosya.txt
sed -i.bak 's/eski/yeni/g' dosya.txt

# macOS (BSD sed):
sed -i '' 's/eski/yeni/g' dosya.txt
sed -i .bak 's/eski/yeni/g' dosya.txt

Bu farkı bilmemek cross-platform script yazan herkesin başını ağrıtır. macOS’ta GNU sed kullanmak istiyorsanız brew install gnu-sed ile kurabilir, gsed komutuyla çağırabilirsiniz.

Hold Space: Gelişmiş Kullanım

sed’de iki tür bellek alanı vardır. Birincisi sürekli bahsettiğimiz “pattern space”, ikincisi ise “hold space”. Hold space, işlemler arasında veri saklamanızı sağlar.

h/H: Pattern space’i hold space’e kopyala/ekle g/G: Hold space’i pattern space’e kopyala/ekle x: Pattern space ile hold space’i yer değiştir

Pratik bir örnek, dosya içeriğini tersine çevirmek:

# Dosyanın satırlarını ters sıraya diz (tac komutu alternatifi):
sed -n '1!G;h;$p' dosya.txt

Bu biraz kafa karıştırıcı görünebilir. Açıklayalım: Her satırda (ilk satır hariç) hold space içeriğini pattern space’in sonuna ekle, sonra pattern space’i hold space’e kopyala. Dosyanın son satırında pattern space içeriğini yazdır.

Gerçek Dünya Senaryosu 4: Ansible ve Shell Script Entegrasyonu

DevOps çalışmalarında sed genellikle diğer araçlarla birlikte kullanılır. Örneğin bir deployment script’i:

#!/bin/bash

APP_VERSION="2.4.1"
DB_HOST="db.production.example.com"
CACHE_HOST="redis.production.example.com"

# Template konfigürasyon dosyasını production için hazırla:
cp config/app.conf.template config/app.conf

sed -i 
    -e "s/__APP_VERSION__/${APP_VERSION}/g" 
    -e "s/__DB_HOST__/${DB_HOST}/g" 
    -e "s/__CACHE_HOST__/${CACHE_HOST}/g" 
    -e "s/__ENVIRONMENT__/production/g" 
    config/app.conf

echo "Konfigürasyon dosyası hazırlandı:"
grep -E "VERSION|HOST|ENVIRONMENT" config/app.conf

Bu pattern (template dosyası + sed ile değer doldurma) basit deployment senaryolarında Ansible veya Helm gibi ağır araçlara güzel bir alternatif oluşturuyor.

Pratik Öneriler ve Yaygın Hatalar

Önce test et, sonra uygula: -i kullanmadan önce komutu çalıştırıp çıktıyı gözle. Çıktı doğruysa -i ekle.

Yedek almayı alışkanlık edin: -i.bak yazmak çok az zaman alıyor ama sizi büyük sıkıntılardan kurtarıyor. Özellikle production’da asla yedeksiz -i kullanmayın.

Karmaşık işlemler için awk veya Python düşünün: sed metin değiştirme için mükemmel ama çok karmaşık logic gerektiren işlemlerde okunaksız hale geliyor. Mesela koşullu çok adımlı dönüşümler için awk daha okunabilir kod üretiyor.

Büyük dosyalarda sed performansı: sed stream tabanlı çalıştığından büyük dosyaları RAM’e almadan işler. 10GB’lık log dosyasında bile rahatça çalışır. Bu açıdan Python veya editörlerden çok üstün.

Özel karakterleri escape edin: ., *, [, gibi regex özel karakterlerini literal olarak kullanmak istiyorsanız önlerine koyun.

# "192.168.1.1" literal olarak ara (. her karakteri eşleştirir):
sed 's/192.168.1.1/10.0.0.1/g' dosya

# Doğru yol (her nokta escape edildi):
sed 's/192.168.1.1/10.0.0.1/g' dosya

sed Script Dosyaları

Uzun ve karmaşık sed komutlarını bir dosyaya yazıp yönetmek çok daha temiz bir yaklaşım:

# temizlik.sed dosyası oluştur:
cat > temizlik.sed << 'EOF'
# Yorum satırlarını sil
/^#/d
# Boş satırları sil
/^$/d
# Baştaki ve sondaki boşlukları temizle
s/^[[:space:]]*//
s/[[:space:]]*$//
# Çift boşlukları tekle
s/  */ /g
EOF

# Kullan:
sed -f temizlik.sed ham_veri.txt > temiz_veri.txt

# Birden fazla dosyaya uygula:
for dosya in /data/konfig/*.conf; do
    sed -i.bak -f temizlik.sed "$dosya"
done

Sonuç

sed, sysadmin araç kutusunda her zaman birinci sıraya yakın bir yerde durmalı. Öğrenme eğrisi başlangıçta biraz dik görünebilir, özellikle regular expression kısmı, ama bu yatırımın getirisi çok yüksek. Günde onlarca kez kopyala-yapıştır yapacağınız işlemleri tek satır sed komutuyla halledebilirsiniz.

En önemli nokta şu: sed’i gerçek senaryolarda kullandıkça zihninizde kalıp komutlar oluşmaya başlıyor. “Yorum satırlarını sil” için sed '/^#/d', “boş satırları temizle” için sed '/^$/d', “global değiştir” için sed 's/eski/yeni/g' artık düşünmeden yazar hale geliyorsunuz. O noktaya gelince terminal karşısındaki verimliliğiniz ciddi anlamda artıyor.

grep ile buldunuz, sed ile dönüştürdünüz, awk ile analiz ettiniz. Bu üçlüyü birlikte kullanabildiğinizde Linux metin işleme konusunda gerçekten güçlü bir sysadmin profiline ulaşıyorsunuz. Bir sonraki yazıda awk’ı ele alacağız ve bu üçlüyü bir arada kullandığımız senaryolarla konuyu taçlandıracağız.

Yorum yapın