00 find zihinsel modeli
find üç kavramı birleştirir: nereye bakacağını, neyi arayacağını, bulunca ne yapacağını.
find [arama-yolu] [testler] [aksiyonlar] Yol: . / /home/user/src (ağaç kökü) Testler: -name -type -size -mtime -perm -user … Aksiyonlar: -print -exec -delete -ls (default: -print)
Testler soldan sağa değerlendirilir, mantıksal AND ile birleştirilir. Kısa devre değerlendirmesi yapılır — ilk test başarısız olursa diğerleri atlanır. Bunu performans için kullanabilirsin: ucuz ve çok seçici testi önce yaz.
# Temel yapı
find . -name '*.log' # mevcut dizin altındaki .log dosyaları
find /var/log -name '*.log' # /var/log altında
find /home /tmp -name '*.tmp' # birden fazla yol
# Mantıksal operatörler
find . -name '*.log' -and -size +1M # her iki koşul da
find . -name '*.log' -or -name '*.txt' # ya biri ya diğeri
find . -not -name '*.log' # .log değil (! ile de yazılır)
find . ! -name '*.log' # aynısı
-and ve -or yazmak zorunlu değil: iki test yan yana yazıldığında find otomatik AND uygular. find . -name '*.log' -size +1M ile find . -name '*.log' -and -size +1M aynıdır.
01 İsim ve yol testleri
Dosyayı adına ya da tam yoluna göre filtrele.
* ? []. Alıntı zorunlu — kabuk yorumlamasını önler.-regextype posix-extended ile ERE aktifleştirilir.# Glob karakterlerini alıntılamazsan kabuk açar, find görmez!
find . -name '*.py' # doğru
find . -name *.py # YANLIŞ — kabuk genişletir
# Tek karakterlik joker
find . -name 'config?.yaml' # config1.yaml, configA.yaml vb.
# Karakter sınıfı
find . -name '[0-9]*.log' # rakamla başlayan .log dosyaları
# test/ veya tests/ dizini içindeki Python dosyaları
find . -path '*/test*/*.py'
# Regex: tarihli log dosyaları (YYYY-MM-DD.log)
find /var/log -regextype posix-extended -regex '.*[0-9]{4}-[0-9]{2}-[0-9]{2}\.log'
find . -name *.py yazarsan kabuk *.py'yi önce genişletir: eğer mevcut dizinde main.py ve utils.py varsa komut find . -name main.py utils.py'a dönüşür — ki bu sözdizimi hatasıdır. Her zaman '*.py' yaz.
02 Tip ve boyut — -type, -empty, -size
Dosya mı, dizin mi, symlink mi? Boş mu? Ne kadar büyük?
-type
# Sadece dosyalar (dizinleri atla)
find . -type f -name '*.conf'
# Sadece dizinler
find . -type d -name 'test*'
# Kırık symlink'ler (hedef yok)
find . -type l ! -e
-empty
# Boş dosyalar
find . -type f -empty
# Boş dizinler
find . -type d -empty
-size
c=byte, k=kibibyte, M=mebibyte, G=gibibyte. Kesin eşleşme.# 100 MB üstü dosyalar
find /var -type f -size +100M
# 1 kB ile 1 MB arası
find . -type f -size +1k -size -1M
# Tam olarak 0 byte (boş dosya) — -empty ile eşdeğer
find . -size 0
03 Zaman testleri
Dosyaları ne zaman değiştirildiğine göre filtrele — yedek ve temizleme işlemlerinin can damarı.
# 7 günden eski .log dosyaları
find /var/log -type f -name '*.log' -mtime +7
# Son 24 saat içinde değiştirilen dosyalar
find . -type f -mtime -1
# Son 30 dakikada değiştirilen
find . -type f -mmin -30
# ref.txt'den daha yeni dosyalar
find . -newer ref.txt
# 30 günden eski .log'ları sil
find /var/log/app -type f -name '*.log' -mtime +30 -delete
-mtime +7 → 7 günden daha eski (7*24 saatten büyük). -mtime -7 → 7 günden daha yeni. -mtime 7 → tam olarak 7. gün (6-7 gün arası). Çoğu senaryoda + veya - kullanırsın.
Önce -delete olmadan çalıştır, çıktıyı kontrol et, sonra ekle. -delete aksiyon olarak en sona gelir ve geri alınamaz.
04 Sahiplik ve izin — -user, -group, -perm
Kimin dosyası olduğunu ve izinlerin ne olduğunu kontrol et.
-perm 644 → tam 644.-perm -222 → herkes yazabilir (sticky dahil).-perm /111 → herhangi biri çalıştırabilir.# alice kullanıcısının dosyaları
find /home -user alice -type f
# Herkesin yazabildiği tehlikeli dosyalar
find /etc -perm -o+w -type f
# SUID biti set edilmiş çalıştırılabilirler
find /usr/bin -perm -4000 -type f
# 777 izinli (tam açık) dosyalar
find . -perm 777 -type f
# UID'siz sahipsiz dosyalar
find /home -nouser
SUID biti olan dosyalar root yetkileriyle çalışır. Sisteminizde beklenmedik SUID dosyası varsa güvenlik riski olabilir. find / -perm -4000 -type f 2>/dev/null ile tam listeyi çekin.
05 -prune — bir dizini atla
node_modules, .git, vendor gibi büyük dizinleri taramanı için -prune şart.
find varsayılan olarak tüm alt dizinlere iner. -prune bir dizini seçer ama içine girmez.
# node_modules hariç tüm .js dosyaları
find . -name 'node_modules' -prune -o -name '*.js' -print
# .git ve target dizinlerini hariç tut
find . \( -name '.git' -o -name 'target' \) -prune \
-o -name '*.rs' -print
# Sadece derinlik sınırla (-maxdepth)
find . -maxdepth 2 -name '*.conf'
find . -mindepth 2 -maxdepth 4 -name '*.py'
-name 'node_modules' -prune -o -name '*.js' -print okunuşu: "adı node_modules ise prune et (geç) VEYA adı *.js ise print et". -o kısa devre değerlendirmesi yapar: prune edilen dizin için -name '*.js' testi hiç çalışmaz. -print yazmak zorunlu — yoksa prune edilen dizin de yazdırılır.
-maxdepth 2 tüm ağacı sınırlar — belirli bir alt dizini değil. Sadece tek bir "kötü" dizini atlamak istiyorsan -prune daha hedeflidir.
06 -exec: üç farklı yol
find bulduğu dosyalara bir komut çalıştırabilir. Ama üç farklı yol var ve aralarındaki fark önemli.
Yol 1: -exec cmd {} \;
# Her dosya için ayrı komut çalıştır
find . -name '*.log' -exec gzip {} \;
# Dosyaların detayını göster
find . -type f -size +10M -exec ls -lh {} \;
{} bulunan dosyanın yeri, \; komutun sonunu belirtir. Her dosya için ayrı bir süreç başlatılır — yüzlerce dosya varsa yüzlerce süreç demek.
Yol 2: -exec cmd {} + (tercih edilen)
# Tüm dosyaları tek komuta argüman olarak ver
find . -name '*.log' -exec gzip {} +
# xargs'a eşdeğer ama daha güvenli
find . -type f -size +10M -exec ls -lh {} +
find tüm eşleşmeleri biriktirip tek bir komut çağrısıyla gönderir: gzip dosya1.log dosya2.log dosya3.log. Çok daha hızlı. \; yerine + kullanmak genellikle doğru tercihtir.
Yol 3: | xargs
# Temel pipe + xargs
find . -name '*.log' | xargs gzip
# Paralel çalıştır (-P ile)
find . -name '*.jpg' | xargs -P4 -I{} convert {} {}.webp
Basit pipe + xargs My File.log gibi boşluklu adları ikiye böler. Çözüm bir sonraki bölümde: -print0 | xargs -0.
| Yol | Süreç sayısı | Boşluklu ad güvenli? | Ne zaman kullan |
|---|---|---|---|
| -exec {} \; | N süreç | Evet | Komut paralel çalışırken ya da her dosya için ayrı işlem şartsa |
| -exec {} + | Az süreç | Evet | Genel kullanım için varsayılan tercih |
| | xargs | Az süreç | Hayır* | -P ile paralel çalışma veya ek xargs flag'leri gerektiğinde |
| | xargs -0 | Az süreç | Evet | Boşluklu adlar + xargs istediğinde (-print0 ile birlikte) |
07 -print0 ve xargs -0
Dosya adlarında boşluk, tab ve newline olabilir. Bunu güvenli şekilde handle etmek için NUL ayırıcı kullan.
Varsayılan olarak find her yolu newline ile ayırır. "My Photo 2026.jpg" gibi bir dosya adı pipe'tan geçerken newline yoktur ama boşluk vardır — ve xargs boşluğu ayırıcı sayar, dosyayı ikiye böler.
# Güvensiz (boşluklu adlarda bozulur)
find . -name '*.jpg' | xargs cp -t /backup/
# Güvenli — NUL ayırıcı (ASCII 0)
find . -name '*.jpg' -print0 | xargs -0 cp -t /backup/
# -0 kısa adı: --null
find . -type f -mtime +30 -print0 | xargs -0 rm
# Paralel sıkıştırma — 4 paralel iş, boşluk güvenli
find . -name '*.log' -print0 | xargs -0 -P4 gzip
-print0 — find her dosya adını NUL karakteriyle (\0, ASCII 0) sonlandırır. NUL, bir dosya adında hiçbir zaman bulunamaz — bu yüzden tek güvenli ayırıcıdır. xargs -0 de NUL'ları ayırıcı sayar. Boşluk, tab, newline hepsi dosya adının parçası olarak işlenir.
xargs kullanıyorsan her zaman -print0 | xargs -0 ikili. Dosya adlarınızda hiç boşluk olmasa bile — ileriye dönük güvenlik için alışkanlık edin.
08 Birleşik örnekler
Gerçek dünya: birden fazla testi birleştiren, -exec ve xargs kullanan senaryolar.
Log temizleme
# 30 günden eski .log'ları gzip'le (önce test et)
find /var/log/app -type f -name '*.log' -mtime +30
# Tamam, gerçekten yap
find /var/log/app -type f -name '*.log' -mtime +30 -exec gzip {} +
# 90 günden eski .gz'leri sil
find /var/log/app -type f -name '*.log.gz' -mtime +90 -delete
Büyük dosya bul, boyutla listele
# /home altında 500MB üstü dosyalar, okunabilir boyutla
find /home -type f -size +500M -exec ls -lh {} + | sort -k5 -hr
Son 7 günde değişen .py dosyalarını grep ile tara
find src/ -name '*.py' -mtime -7 -print0 \
| xargs -0 grep -l 'TODO'
Boş dizinleri temizle
# Önce listele
find . -type d -empty
# Sonra sil (rmdir güvenli — boş olmayan dizini silmez)
find . -type d -empty -exec rmdir {} +
node_modules hariç büyük dosya tara
find . -name 'node_modules' -prune \
-o -type f -size +1M -print
Hatırlanacaklar
- Glob desenlerini her zaman alıntıla:
'*.log' - Testler AND ile birleşir (yazmak zorunlu değil);
-or/!ile alternatif/negasyon -mtime +7= 7 günden eski,-mtime -7= son 7 günde değişen-exec {} +→ tek komuta toplar (hızlı),-exec {} \;→ her biri için ayrı- xargs kullanırken
-print0 | xargs -0→ boşluklu dosya adı güvenliği -prune -o -name '*.py' -print→ belirli dizini atlama kalıbı-deleteöncesi her zaman bir kez without-deleteçalıştır
Bulduğun dosyalara metin işleme uygulayacaksan: grep, sed, awk rehberi.