Bash tools
TEKNİK REHBER BASH TOOLS DOSYA SİSTEMİ 2026

find — dosya sistemi
sorguları.

find'ın temelini herkes bilir. Ama -prune, -exec {} +, xargs -0 ve mtime kombinasyonlarını bilerek kullanmak — bu rehberin konusu bu.

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.

bash
# 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ı
NE OLUYOR

-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.

-name 'desen'
dosya adı (yalnızca son bileşen) desene uyuyor mu? Glob karakterleri: * ? []. Alıntı zorunlu — kabuk yorumlamasını önler.
-iname 'desen'
-name gibi ama büyük/küçük harf duyarsız.
-path 'desen'
tam yol (./src/utils/helper.py gibi) desene uyuyor mu? Glob kullanabilir.
-ipath 'desen'
-path'ın harf duyarsız versiyonu.
-regex 'desen'
tam yola regex uygular (POSIX ERE). -regextype posix-extended ile ERE aktifleştirilir.
bash
# 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'
DİKKAT — alıntı zorunlu

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

-type f
regular file (normal dosya).
-type d
directory (dizin).
-type l
symbolic link.
-type s
socket.
-type p
named pipe (FIFO).
-type b / c
block / character device.
bash
# 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

bash
# Boş dosyalar
find . -type f -empty

# Boş dizinler
find . -type d -empty

-size

-size N[cwbkMG]
c=byte, k=kibibyte, M=mebibyte, G=gibibyte. Kesin eşleşme.
-size +N
N'den büyük.
-size -N
N'den küçük.
-size +1M -size -100M
iki test birlikte → 1 ile 100 MB arası.
bash
# 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ı.

-mtime N
son değiştirme zamanı. N gün önce (modif-time). +N → N günden eski, -N → N günden yeni, N → tam N gün önce (24h penceresinde).
-mmin N
aynısı ama dakika biriminde. +N dakikadan eski, -N dakikadan yeni.
-atime N
son erişim zamanı (access-time). Birçok sistemde noatime mount seçeneğiyle güncellenmiyor olabilir.
-ctime N
inode değişme zamanı (change-time) — içerik veya metadata (izin, sahip) değişikliği. Oluşturma tarihi değil.
-newer dosya
belirtilen dosyadan daha yeni değiştirilen dosyalar. Makefile mantığı için kullanışlı.
bash
# 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
+N / -N / N farkı kritik

-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.

-delete dikkat

Ö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.

-user isim/uid
kullanıcı adı veya UID'ye göre filtrele.
-group isim/gid
grup adı veya GID'ye göre filtrele.
-nouser
UID'si tanımsız dosyalar (silinmiş kullanıcı).
-nogroup
GID'si tanımsız dosyalar.
-perm mode
tam eşleşme. -perm 644 → tam 644.
-perm -mode
en azından bu izinler set edilmiş. -perm -222 → herkes yazabilir (sticky dahil).
-perm /mode
herhangi bir bit eşleşiyor. -perm /111 → herhangi biri çalıştırabilir.
bash
# 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 güvenlik taraması

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.

bash
# 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'
NE OLUYOR

-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 ile karşılaştırma

-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 {} \;

bash
# 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)

bash
# 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

bash
# Temel pipe + xargs
find . -name '*.log' | xargs gzip

# Paralel çalıştır (-P ile)
find . -name '*.jpg' | xargs -P4 -I{} convert {} {}.webp
DİKKAT — boşluklu dosya adı

Basit pipe + xargs My File.log gibi boşluklu adları ikiye böler. Çözüm bir sonraki bölümde: -print0 | xargs -0.

YolSüreç sayısıBoşluklu ad güvenli?Ne zaman kullan
-exec {} \;N süreçEvetKomut paralel çalışırken ya da her dosya için ayrı işlem şartsa
-exec {} +Az süreçEvetGenel kullanım için varsayılan tercih
| xargsAz süreçHayır*-P ile paralel çalışma veya ek xargs flag'leri gerektiğinde
| xargs -0Az süreçEvetBoş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.

bash
# 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
NE OLUYOR

-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.

Kural

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

bash
# 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

bash
# /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

bash
find src/ -name '*.py' -mtime -7 -print0 \
  | xargs -0 grep -l 'TODO'

Boş dizinleri temizle

bash
# Ö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

bash
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.