find Komutu ile Eski Arşivleri Otomatik Silme

Disk dolunca ne olur? Web sunucusu çöker, veritabanı yazamaz, log dosyaları kesilir. Bunu genellikle gece yarısı, telefon çalarken öğrenirsiniz. Yıllarca biriken eski yedek arşivleri, log sıkıştırmaları ve geçici dosyalar sessiz sedasız diskinizi doldurur. İyi haber şu: find komutu ve birkaç satır bash ile bu sorunu tamamen otomatize edebilirsiniz.

find Komutunun Temel Mantığı

find komutu, dosya sisteminde arama yaparken aslında çok daha fazlasını yapabilir. Çoğu sysadmin find / -name "*.log" seviyesinde kullanır ve bırakır. Ama find‘ın asıl gücü -exec, -delete ve -mtime gibi parametrelerle ortaya çıkıyor.

Eski arşivleri silmek için en çok kullandığımız parametreler şunlar:

  • -mtime +N: Son N günden daha önce değiştirilmiş dosyaları bulur
  • -mtime -N: Son N gün içinde değiştirilmiş dosyaları bulur
  • -atime +N: Son N günden daha önce erişilmiş dosyaları bulur
  • -ctime +N: Son N günden daha önce inode’u değişmiş dosyaları bulur
  • -name “pattern”: Dosya adı kalıbına göre filtreler
  • -type f: Sadece dosyaları arar (dizin değil)
  • -type d: Sadece dizinleri arar
  • -size +100M: 100 MB’dan büyük dosyaları bulur
  • -delete: Bulunan dosyaları siler (dikkatli kullanın)
  • -exec komut {} ;: Her bulunan dosya için komut çalıştırır

Burada ince bir nokta var: -mtime +30 dediğinizde “tam olarak 30 günden eski” değil, “30 günlük periyodu tamamen geçmiş” dosyaları bulursunuz. Yani aslında 31. günden itibaren başlar. Bu farkı production’da silme yaparken gözden kaçırmayın.

İlk Adım: Silmeden Önce Görmek

Asla direkt silme komutunu çalıştırmayın. Önce ne bulduğunuzu görün. Bu kural her seviyede sysadmin için geçerli.

# 30 günden eski .tar.gz dosyalarını listele, silme
find /backup -type f -name "*.tar.gz" -mtime +30

# Boyutlarıyla birlikte görüntüle
find /backup -type f -name "*.tar.gz" -mtime +30 -exec ls -lh {} ;

# Toplam kapladığı alanı öğren
find /backup -type f -name "*.tar.gz" -mtime +30 | xargs du -ch | tail -1

Son komut özellikle işe yarıyor. “Sileceğim dosyalar kaç GB yer kaplıyor?” sorusuna anında cevap verir. Production’da 200 GB silmeden önce bunu bilmek istersiniz.

Temel Silme Örnekleri

Artık ne sildiğimizi biliyoruz. Şimdi gerçek komutlara geçelim.

# 30 günden eski tüm .tar.gz arşivlerini sil
find /backup -type f -name "*.tar.gz" -mtime +30 -delete

# 60 günden eski .zip dosyalarını sil
find /var/archives -type f -name "*.zip" -mtime +60 -delete

# 7 günden eski sıkıştırılmış log dosyalarını sil
find /var/log -type f ( -name "*.gz" -o -name "*.bz2" ) -mtime +7 -delete

-delete parametresi -exec rm {} ; komutundan daha hızlıdır çünkü her dosya için yeni bir process başlatmaz. Ama her ikisi de işe yarar.

Bazen -delete yerine -exec kullanmak daha fazla kontrol sağlar:

# rm -v ile silinen her dosyayı ekrana yazdır
find /backup -type f -name "*.tar.gz" -mtime +30 -exec rm -v {} ;

# Silinen dosyaları log dosyasına kaydet
find /backup -type f -name "*.tar.gz" -mtime +30 -exec rm -v {} ; >> /var/log/archive_cleanup.log 2>&1

Gerçek Dünya Senaryosu 1: Günlük Yedek Rotasyonu

Diyelim ki her gece bir script ile /backup/daily/ klasörüne yedek alıyorsunuz. Format şöyle: db_backup_2024-01-15.tar.gz. 30 günden eski olanları tutmak istemiyorsunuz.

#!/bin/bash
# /usr/local/bin/cleanup_daily_backups.sh

BACKUP_DIR="/backup/daily"
RETENTION_DAYS=30
LOG_FILE="/var/log/backup_cleanup.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

echo "[$DATE] Yedek temizleme başladı" >> "$LOG_FILE"

# Kaç dosya silineceğini say
COUNT=$(find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +"$RETENTION_DAYS" | wc -l)
echo "[$DATE] Silinecek dosya sayısı: $COUNT" >> "$LOG_FILE"

# Toplam boyutu hesapla
SIZE=$(find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +"$RETENTION_DAYS" | xargs du -ch 2>/dev/null | tail -1 | cut -f1)
echo "[$DATE] Kazanılacak alan: $SIZE" >> "$LOG_FILE"

# Sil
find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +"$RETENTION_DAYS" -exec rm -v {} ; >> "$LOG_FILE" 2>&1

echo "[$DATE] Temizleme tamamlandı" >> "$LOG_FILE"

Bu scripti crontab’a ekleyin:

# Her gece 02:00'de çalıştır
0 2 * * * /usr/local/bin/cleanup_daily_backups.sh

Gerçek Dünya Senaryosu 2: Çok Seviyeli Yedek Stratejisi

Kurumsal ortamlarda sıkça kullanılan bir yaklaşım: günlük, haftalık ve aylık yedekleri farklı sürelerde tutmak.

#!/bin/bash
# /usr/local/bin/tiered_backup_cleanup.sh

# Günlük yedekler: 7 gün tut
find /backup/daily -type f -name "*.tar.gz" -mtime +7 -delete

# Haftalık yedekler: 30 gün tut
find /backup/weekly -type f -name "*.tar.gz" -mtime +30 -delete

# Aylık yedekler: 365 gün tut
find /backup/monthly -type f -name "*.tar.gz" -mtime +365 -delete

# Boş kalan dizinleri de temizle
find /backup -type d -empty -not -path "/backup" -delete

Son satırdaki -not -path "/backup" önemli. Ana dizini silmemek için bu kontrolü koyuyoruz. Boş kalan alt klasörleri temizler ama ana backup dizinine dokunmaz.

Boyuta Göre Eski Arşiv Silme

Bazen tarih önemli değil, boyut önemlidir. “100 MB’dan büyük ve 15 günden eski her arşivi sil” diyebilirsiniz.

# 15 günden eski ve 100MB'dan büyük dosyaları bul
find /var/archives -type f -mtime +15 -size +100M

# Bul ve sil
find /var/archives -type f -mtime +15 -size +100M -delete

# Birden fazla uzantıyı hedefle
find /var/archives -type f -mtime +15 -size +100M 
  ( -name "*.tar.gz" -o -name "*.tar.bz2" -o -name "*.zip" -o -name "*.7z" ) 
  -delete

Parantez içindeki -o (OR) operatörü birden fazla uzantıyı aynı anda hedeflemenizi sağlar. Backslash ile escape etmeyi unutmayın.

find ile xargs Kombinasyonu

Çok fazla dosya varsa -exec yavaşlayabilir. Her dosya için ayrı process açar. xargs ile bunu toplu yapabilirsiniz:

# xargs ile toplu silme (çok daha hızlı)
find /backup -type f -name "*.tar.gz" -mtime +30 | xargs rm -f

# Dosya adlarında boşluk varsa (nadiren olur ama olabilir)
find /backup -type f -name "*.tar.gz" -mtime +30 -print0 | xargs -0 rm -f

# Paralel silme (birden fazla thread)
find /backup -type f -name "*.tar.gz" -mtime +30 -print0 | xargs -0 -P 4 rm -f

-print0 ve xargs -0 kombinasyonu dosya adlarında özel karakter veya boşluk olduğunda güvenli çalışır. Production’da her zaman bunu tercih edin.

Belirli Dizinleri Atlama

Bazen bir dizinin altındaki her şeyi taramak ama bazı klasörleri atlamak istersiniz. Örneğin /backup altındaki her şeyi tararken /backup/critical klasörüne dokunmayın.

# critical dizinini atlayarak temizle
find /backup -path /backup/critical -prune -o -type f -name "*.tar.gz" -mtime +30 -delete

# Birden fazla dizini atla
find /backup 
  ( -path /backup/critical -o -path /backup/permanent ) 
  -prune -o 
  -type f -name "*.tar.gz" -mtime +30 
  -delete

-prune parametresi o dizine girmeyi engeller. -o ise “ya da” anlamında devam etmesini sağlar. Sözdizimi biraz garip görünüyor ama mantığı şu: “eğer bu yolsa, buda (-prune), yoksa devam et”.

Güvenli Silme: dry-run Yaklaşımı

Production sunucularda silme scriptinizi ilk kez çalıştırmadan önce mutlaka dry-run yapın.

#!/bin/bash
# Dry-run modu ile güvenli temizleme scripti

DRY_RUN=true  # Gerçek silme için false yapın
BACKUP_DIR="/backup"
DAYS=30

if [ "$DRY_RUN" = true ]; then
    echo "=== DRY RUN MODU - Hiçbir şey silinmiyor ==="
    find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +"$DAYS" -print
    echo ""
    echo "Toplam alan:"
    find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +"$DAYS" | xargs du -ch 2>/dev/null | tail -1
else
    echo "=== GERÇEK SİLME BAŞLIYOR ==="
    find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +"$DAYS" -delete
    echo "Tamamlandı."
fi

Bu scripti önce DRY_RUN=true ile çalıştırıp çıktıyı inceleyin. Her şey doğruysa DRY_RUN=false yapıp tekrar çalıştırın.

Disk Dolduğunda Tetiklenen Otomatik Temizlik

Daha akıllı bir yaklaşım: disk belirli bir doluluk oranına gelince temizliği başlat.

#!/bin/bash
# /usr/local/bin/smart_archive_cleanup.sh

BACKUP_DIR="/backup"
THRESHOLD=85  # Disk %85 dolunca temizle
RETENTION_DAYS=30
LOG="/var/log/smart_cleanup.log"

# Mevcut disk kullanımını al (yüzde olarak)
DISK_USAGE=$(df "$BACKUP_DIR" | awk 'NR==2 {print $5}' | tr -d '%')

echo "[$(date)] Disk kullanımı: %$DISK_USAGE" >> "$LOG"

if [ "$DISK_USAGE" -gt "$THRESHOLD" ]; then
    echo "[$(date)] Eşik aşıldı (%$THRESHOLD), temizleme başlıyor..." >> "$LOG"
    
    # Önce en eski dosyalardan başla
    find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +"$RETENTION_DAYS" 
        -exec rm -v {} ; >> "$LOG" 2>&1
    
    # Hala yüksekse daha agresif temizle
    DISK_USAGE_AFTER=$(df "$BACKUP_DIR" | awk 'NR==2 {print $5}' | tr -d '%')
    if [ "$DISK_USAGE_AFTER" -gt "$THRESHOLD" ]; then
        echo "[$(date)] Hala yüksek, 15 günlük arşivler de siliniyor..." >> "$LOG"
        find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +15 
            -exec rm -v {} ; >> "$LOG" 2>&1
    fi
    
    echo "[$(date)] Temizleme sonrası disk: %$DISK_USAGE_AFTER" >> "$LOG"
else
    echo "[$(date)] Temizleme gerekmiyor." >> "$LOG"
fi

Bu scripti her saat crontab ile çalıştırabilirsiniz:

0 * * * * /usr/local/bin/smart_archive_cleanup.sh

find ile Arşiv İçeriği Kontrolü

Silmeden önce arşivin geçerli olup olmadığını kontrol etmek isteyebilirsiniz. Bozuk bir arşivi silmek sorun değil ama geçerli bir arşivi kazara silmek can sıkıcı.

#!/bin/bash
# Bozuk arşivleri tespit et ve sil

find /backup -type f -name "*.tar.gz" -mtime +30 | while read -r file; do
    if tar -tzf "$file" &>/dev/null; then
        echo "Geçerli arşiv, siliniyor: $file"
        rm -f "$file"
    else
        echo "UYARI: Bozuk arşiv, atlanıyor: $file"
    fi
done

Bu yaklaşım biraz daha yavaş çünkü her arşivi test ediyor ama kritik yedekleme sistemlerinde bu ekstra güvence değer.

Yaygın Hatalar ve Çözümleri

find komutunu root ile çalıştırırken dikkatli olun. -delete yerine -exec rm -rf {} ; kullandığınızda ve yanlış bir path yazarsanız ciddi zarar verebilirsiniz. find / ile başlayan komutlarda ekstra dikkatli olun.

mtime ile atime karıştırmayın. mtime dosyanın içeriğinin değişme zamanını, atime son erişim zamanını gösterir. Arşiv sistemlerinde genellikle mtime daha güvenilirdir. Bazı sistemlerde noatime mount seçeneği kullanıldığında atime hiç güncellenmez.

Symlink’lere dikkat. Varsayılan olarak find symlink’leri takip etmez. Ama silme işleminde sembolik bağlantıyı silerseniz, asıl dosya yerinde kalır. Bu bazen beklediğiniz alanı kazanamamanıza yol açar.

# Sadece gerçek dosyaları sil, symlink'leri atla
find /backup -type f -not -type l -name "*.tar.gz" -mtime +30 -delete

Dosya sayısı çok fazlaysa Argument list too long hatası alırsınız. Bu durumda xargs kullanın veya -delete parametresine geçin.

Monitoring: Ne Silindi, Ne Kaldı?

Temizleme scriptinizi çalıştırdıktan sonra durumu raporlayan bir kontrol ekleyin:

#!/bin/bash
# cleanup_report.sh

BACKUP_DIR="/backup"
echo "=== Yedek Dizin Raporu: $(date) ==="
echo ""
echo "Toplam alan kullanımı:"
du -sh "$BACKUP_DIR"
echo ""
echo "Dosya sayısına göre dağılım:"
find "$BACKUP_DIR" -type f -name "*.tar.gz" | wc -l | xargs echo "  .tar.gz:"
find "$BACKUP_DIR" -type f -name "*.zip" | wc -l | xargs echo "  .zip:"
echo ""
echo "En eski 5 arşiv:"
find "$BACKUP_DIR" -type f -name "*.tar.gz" -printf '%T+ %pn' | sort | head -5
echo ""
echo "En büyük 5 arşiv:"
find "$BACKUP_DIR" -type f -name "*.tar.gz" -exec ls -s {} ; | sort -rn | head -5

-printf '%T+ %pn' formatı tarih sırasına göre sıralamayı kolaylaştırır. Bu komutu haftalık olarak crontab’a alıp e-posta ile gönderebilirsiniz.

Sonuç

find komutu sysadmin’in en güvenilir araçlarından biri. Disk yönetimi söz konusu olduğunda eski arşivleri otomatik temizlemek, gecenin körü paniklemekten çok daha iyidir.

Özetlemek gerekirse:

  • Her zaman -delete veya -exec rm çalıştırmadan önce komutunuzu salt listeleme moduyla test edin
  • mtime +N parametresini doğru anladığınızdan emin olun, N+1. günden itibaren seçer
  • Silme işlemlerini log dosyasına yazın, neyin silindiğini takip edin
  • xargs -0 ve -print0 kombinasyonunu özel karakterli dosya adlarında kullanın
  • Disk doluluk eşiğine dayalı tetikleyici scriptler production’da çok daha akıllıca çalışır
  • Kritik yedekleri ayrı bir dizinde tutun ve o dizini -prune ile dışarıda bırakın

Bu scriptleri ihtiyacınıza göre uyarlayın ve crontab’a alın. Disk yönetimi artık sizin için değil, kendisi için çalışsın.

Yorum yapın