sed ile Satır Aralığı Seçimi ve Blok Tabanlı Metin Düzenleme
Yıllar önce bir üretim sunucusunda 50.000 satırlık bir config dosyasının ortasındaki belirli bir bloğu elle düzenlemek zorunda kaldığımda, sed‘in satır aralığı seçiminin ne kadar kritik bir beceri olduğunu anladım. O gün terminale sarılıp saatlerce uğraşmak yerine tek bir komutla işi bitirseydim, hem zaman kazanırdım hem de o hata ayıklama seansından kurtulurdum. Bu yazıda sed‘in en güçlü ama en az konuşulan özelliklerinden biri olan satır aralığı seçimi ve blok tabanlı metin düzenleme konusunu gerçek dünya örnekleriyle ele alacağız.
sed’in Adres Mekanizmasını Anlamak
sed (stream editor), metni satır satır işler ve her satırda hangi işlemi uygulayacağını belirlemek için adres kavramını kullanır. Bir adres vermezseniz komut tüm satırlara uygulanır. Adres verdiğinizde ise sadece belirttiğiniz satır veya aralıkta çalışır.
Adres türleri temelde şunlardır:
- Satır numarası:
5(sadece 5. satır) - Son satır:
$(dosyanın son satırı) - Regex:
/pattern/(desene uyan satırlar) - Aralık:
başlangıç,bitiş(iki adres arası) - Adım:
first~step(ilk satırdan başlayarak her N adımda bir)
Basit bir örnekle başlayalım. Elimizde şu dosya olsun:
cat /tmp/ornek.txt
# 1. satır: başlık
# 2. satır: versiyon bilgisi
# 3. satır: boş
# 4. satır: asıl config
# 5. satır: database
# 6. satır: cache
# 7. satır: son
Sadece 3. ve 6. satırlar arasını yazdırmak için:
sed -n '3,6p' /tmp/ornek.txt
-n bayrağı varsayılan çıktıyı bastırır, p komutu ise eşleşen satırları açıkça yazdırır. Bu ikili birlikte çok sık kullanılır.
Satır Numarasıyla Aralık Seçimi
En temel kullanım satır numaralarıyla çalışmaktır. Günlük sysadmin hayatında log dosyalarında belirli zaman dilimlerini çekmek ya da config bloklarını izole etmek için bunu sürekli kullanırsınız.
# 10. satırdan 20. satıra kadar yazdır
sed -n '10,20p' /var/log/syslog
# İlk 5 satırı sil (dosyayı değiştirmeden)
sed '1,5d' /etc/hosts
# Sadece son satırı göster ($ sembolü son satır anlamına gelir)
sed -n '$p' /etc/passwd
# 5. satırdan dosya sonuna kadar sil
sed '5,$d' uygulama.conf
Burada dikkat edilmesi gereken nokta: sed '1,5d' komutu dosyayı değiştirmez, sonucu stdout’a yazar. Eğer dosyayı yerinde değiştirmek istiyorsanız -i bayrağını kullanmalısınız. Ama ben her zaman önce -i olmadan test ederim, sonra emin olduğumda -i eklerim. Üretim sisteminde tersi sırayı deneyenler var mı aramızda? O anın stresini biliyoruz.
# Önce test et
sed '1,5d' uygulama.conf
# Emin olduktan sonra dosyayı değiştir
sed -i '1,5d' uygulama.conf
# Ya da yedek alarak değiştir (macOS ve GNU sed her ikisinde çalışır)
sed -i.bak '1,5d' uygulama.conf
Regex Tabanlı Adres Seçimi
Satır numarasını bilmediğinizde, yani dinamik dosyalarda çalışırken regex adresleme hayat kurtarır. Bir başlangıç deseni ve bitiş deseni vererek blok seçimi yapabilirsiniz.
# [database] ile başlayan satırdan [cache] ile başlayan satıra kadar
sed -n '/[database]/,/[cache]/p' app.conf
# BEGIN ile END arasındaki bloğu sil
sed '/^BEGIN/,/^END/d' script.txt
# "server {" ile kapanış "}" arasındaki nginx bloğunu yazdır
sed -n '/server {/,/^}/p' /etc/nginx/nginx.conf
Gerçek bir senaryo: Nginx config dosyasında belirli bir location bloğunu bulmak istiyorsunuz. Dosya 300 satır ve hangi satırda olduğunu bilmiyorsunuz:
sed -n '/location /api//,/^[[:space:]]*}/p' /etc/nginx/sites-available/default
Bu komut /api/ ile başlayan location bloğunu bulur ve kapanan süslü paranteze kadar yazdırır. Ancak iç içe parantezlerde dikkatli olun, sed bağlam bilgisi tutmaz, ilk kapanan parantezde durur.
Adım Tabanlı Seçim: first~step Sözdizimi
Bu özelliği çoğu kişi bilmez ama son derece işlevseldir. GNU sed’e özgü olan bu sözdizimi, belirli aralıklarla satır seçmenizi sağlar.
# Tek satırları yazdır (1'den başla, 2'şer atla)
sed -n '1~2p' dosya.txt
# Çift satırları yazdır
sed -n '2~2p' dosya.txt
# Her 3 satırda bir 1. satırı al (CSV'de her 3. kaydı)
sed -n '1~3p' veri.csv
# 4'er satırlık bloklarda ilk satırı atla, diğerlerini al
sed -n '2~4,4~4p' log.txt
Bunu ne zaman kullanırsınız? Örneğin bir monitoring scripti çıktısını işlerken her çift satırın değer, tek satırların etiket olduğu durumlar sık karşılaşılan bir pattern. Ya da bazı legacy log formatlarında kayıtlar sabit satır sayısıyla ayrılmış olabiliyor.
Blok Tabanlı Düzenleme: Aralıkta Değiştirme
Asıl güç, seçilen aralık içinde değiştirme yapmaktır. Bu, sed‘in gerçek bir metin editörü gibi davrandığı yerdir.
# Sadece 10-20. satırlar arasında "old" kelimesini "new" ile değiştir
sed '10,20s/old/new/g' config.txt
# [section] ile sonraki [section] arasındaki değerleri güncelle
sed '/^[web]/,/^[/{/^[web]/!s/port=.*/port=8080/}' app.ini
# İlk 100 satırdaki comment satırlarını sil
sed '1,100{/^#/d}' büyük-dosya.conf
Süslü parantez ile blok komut gruplama özelliği burada devreye giriyor. Bir adresi seçip ardından {} içinde birden fazla komut uygulayabilirsiniz:
# 5-15. satırlar arasında:
# 1. Boş satırları sil
# 2. Yorum satırlarını sil
# 3. "debug" kelimesini "info" ile değiştir
sed '5,15{
/^$/d
/^#/d
s/debug/info/g
}' uygulama.log
Bu yapı özellikle config dosyası manipülasyonunda son derece güçlü. Bir Ansible playbook yazmadan önce önce sed ile test etmek, çok daha hızlı iterasyon yapmanızı sağlar.
Gerçek Dünya Senaryosu: Apache Config Bloğu Yönetimi
Diyelim ki bir VirtualHost bloğunu başka bir dosyayla değiştirmeniz gerekiyor. Klasik bir sysadmin görevi:
# Önce bloğun başlangıç ve bitiş satır numaralarını bul
grep -n "VirtualHost" /etc/apache2/sites-available/000-default.conf
# Çıktı diyelim ki:
# 1:<VirtualHost *:80>
# 45:</VirtualHost>
# O bloğu sil ve yerine yeni içerik ekle
sed -i '1,45c
<VirtualHost *:80>
ServerName yenisite.com
DocumentRoot /var/www/yeni
</VirtualHost>' /etc/apache2/sites-available/000-default.conf
Ya da daha sağlam bir yöntem, regex ile dinamik bulmak:
# VirtualHost bloğunu regex ile sil
sed -i '/^<VirtualHost/,/^</VirtualHost>/d' /etc/apache2/sites-available/000-default.conf
# Ardından yeni içeriği ekle
cat >> /etc/apache2/sites-available/000-default.conf << 'EOF'
<VirtualHost *:80>
ServerName yenisite.com
DocumentRoot /var/www/yeni
</VirtualHost>
EOF
Satır Aralığında Silme ve İzole Etme
Büyük log dosyalarını işlerken belirli blokları silmek ya da sadece belirli bölümleri almak çok yaygın bir ihtiyaç. İşte pratik örnekler:
# İlk ve son satırı hariç tüm dosyayı yazdır
sed -n '2,${ $!p }' dosya.txt
# Belirli bir hata kodunu içeren bloğu (3 satır bağlamıyla) çıkart
# grep -A3 -B3 kullanamazsınız, sed ile daha fazla kontrol edersiniz:
sed -n '/ERROR 500/{N;N;N;p}' /var/log/app.log
# Çift sayılı satırları sil (tek satırları bırak)
sed '2~2d' dosya.txt
# Dosyanın ortasındaki belirli satır bloğunu başka bir dosyaya kaydet
sed -n '50,100p' büyük.log > orta-kesit.log
Bir log analizi senaryosu: Production’da bir uygulama her gece 02:00-04:00 arasında yavaşlıyor. O zaman aralığındaki log satırlarını çekmek için:
# Önce başlangıç ve bitiş satır numaralarını bul
START=$(grep -n "02:00:00" /var/log/app/production.log | head -1 | cut -d: -f1)
END=$(grep -n "04:00:00" /var/log/app/production.log | tail -1 | cut -d: -f1)
# Sonra sed ile o aralığı çek
sed -n "${START},${END}p" /var/log/app/production.log > gece-analiz.log
echo "Analiz için ${START}-${END} satırları çekildi"
Bu scripti cron’a ekleyip her sabah otomatik rapor alabilirsiniz. Evet, awk ya da grep ile de yapılabilir ama sed‘in satır numarası değişkenine bu kadar temiz entegre olması işi kolaylaştırıyor.
Ters Seçim: Aralık Dışını Hedefleme
! operatörü, seçimin tersini almak için kullanılır. Yani “bu aralık hariç tümü” anlamına gelir:
# 5-10. satırlar HARİÇ tümünü yazdır
sed -n '5,10!p' dosya.txt
# [config] bloğu dışındaki her şeyi sil (sadece bloğu bırak)
sed '/^[config]/,/^[/!d' ayarlar.conf
# İlk satır hariç tüm satırlara numara ekle
sed '1!=' dosya.txt
# Yorum olmayan satırları sil (sadece yorumları bırak)
sed '/^#/!d' script.sh
! operatörü özellikle config dosyası parsing’inde çok işe yarar. Bir INI dosyasından sadece belirli bir section’ı izole etmek istediğinizde:
# Sadece [production] section'ını göster
sed -n '/^[production]/,/^[/{ /^[production]/p; /^[/!p }' config.ini
Bu biraz karmaşık görünebilir. Açalım: [production] ile başlayan bir sonraki section başlığına kadar seç. Bu aralık içinde, section başlığı olan satırı ([production]) yazdır ve diğer section başlıklarını ([) atla. Net bir blok izolasyonu.
c, i, a Komutlarıyla Aralıkta İçerik Ekleme
sed‘in c (change), i (insert), a (append) komutlarını aralıklarla birleştirmek çok güçlü editörleme imkanı sunar:
# 10. satırdan sonra yeni bir satır ekle
sed '10aYeni satır buraya eklendi' dosya.txt
# 5-10. satır bloğunu tamamen değiştir
sed '5,10cBu satırlar yenilendi' dosya.txt
# Regex ile bulunan satırdan önce satır ekle
sed '/^server_name/i# Sunucu yapılandırması aşağıdadır' nginx.conf
Gerçek kullanım: Bir Kubernetes manifest dosyasına belirli bir bölümden sonra yeni bir annotation eklemek:
# metadata: satırından sonra annotation bloğu ekle
sed -i '/^metadata:/a annotations:n app.kubernetes.io/version: "2.1.0"' deployment.yaml
Dikkat: n davranışı GNU sed ve BSD sed arasında farklılık gösterir. macOS’ta çalışıyorsanız bunu aklınızda tutun.
Çok Dosyalı İşlemler ve Performans
sed‘in satır aralığı seçimini birden fazla dosyada veya büyük dosyalarda kullanırken bazı pratik notlar:
# Birden fazla dosyada aynı bloğu düzenle
for conf in /etc/myapp/*.conf; do
sed -i '/^[legacy]/,/^[/d' "$conf"
echo "$conf güncellendi"
done
# find ile birlikte kullan
find /var/log -name "*.log" -exec sed -n '1,50p' {} ; > ilk-satirlar.txt
# Büyük dosyalarda sadece ilgilendiğin bloğa eriştikten sonra çık (q komutu)
sed -n '/START_MARKER/,/END_MARKER/{p; /END_MARKER/q}' dev.log
Son örnekteki q komutu önemli: END_MARKER‘ı bulduğunda işlemi bitirir. 10GB’lık bir log dosyasında aradığınız blok başta ise bu komut sizi binlerce satır gereksiz işlemden kurtarır.
sed Script Dosyaları ile Karmaşık Blok Operasyonları
Birden fazla aralık ve komut kullanacaksanız, bunları bir script dosyasına yazıp -f bayrağıyla çağırmak hem okunabilirliği artırır hem de versiyon kontrolüne koymanızı kolaylaştırır:
cat > temizle.sed << 'EOF'
# İlk 3 satırı (header) sil
1,3d
# Test environment satırlarını temizle
/^ENV=test/,/^ENV=/d
# Boş satırları sil (sadece config bloğu içinde)
/^[config]/,/^[/{
/^$/d
}
# Debug logları kaldır
/DEBUG/d
EOF
# Scripti uygula
sed -f temizle.sed uygulama.conf > uygulama-temiz.conf
Bu yaklaşımı özellikle CI/CD pipeline’larında config dosyası dönüşümleri için çok kullanıyorum. Tek bir sed komutu yerine açıklamalı bir script dosyası, altı ay sonra bakan ekip arkadaşınızın da anlayabileceği bir şey bırakır.
Sonuç
sed‘in satır aralığı seçimi ve blok tabanlı düzenleme özellikleri, metin işleme araç setinin gerçek anlamda güçlü katmanını oluşturuyor. Satır numarasından regex’e, adım seçiminden ters seçime kadar farklı adres mekanizmalarını birleştirebildiğinizde, editör açmadan karmaşık config manipülasyonları yapabiliyorsunuz.
Özellikle şu senaryolarda bu becerilerin farkını net göreceksiniz: büyük log dosyası analizi, deployment sırasında config dosyası dönüşümleri, otomatik belgeleme pipeline’ları ve legacy sistem migrasyonları.
Önerim şu: bir sonraki config değişikliğinde terminale dönün ve sed ile deneyin. İlk başta grep + elle düzenleme kadar hızlı gelmeyebilir. Ama on kez yaptıktan sonra kas hafızası oturacak ve sizi GUI editöre muhtaç olmaktan kurtaracak. Üretim sunucusuna SSH açtığınızda vi yerine doğrudan sed ile ilerlediğinizde hem daha hızlı olacaksınız hem de script edilebilir, tekrarlanabilir bir süreç bırakacaksınız. Bu fark, zamanla biriken en değerli kazanımlardan biri.
