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
-deleteveya-exec rmçalıştırmadan önce komutunuzu salt listeleme moduyla test edin mtime +Nparametresini 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 -0ve-print0kombinasyonunu ö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
-pruneile 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.