Dosya İsmi Toplu Değiştirme: rename Komutu ve Bash Döngüsü

Yüzlerce dosyayı tek tek yeniden adlandırmak zorunda kaldıysanız, bu acıyı iyi biliyorsunuzdur. Müşteriden gelen bir klasörde tüm dosyalar IMG_001.JPG, IMG_002.JPG formatındayken bunları proje adıyla başlayan bir isimlendirme standardına getirmek, ya da bir geliştirici ekibinin ürettiği log dosyalarındaki tarih formatını değiştirmek… Bu tür işler için fareyle uğraşmak saatler alabilir. Ama terminalde doğru araçları kullandığınızda birkaç saniyede bitirirsiniz. Bu yazıda rename komutunu ve bash döngülerini kullanarak toplu dosya yeniden adlandırma işlemlerini her açısıyla ele alacağız.

rename Komutu Nedir?

rename komutu, Linux sistemlerde dosya isimlerini toplu olarak değiştirmek için kullanılan güçlü bir araçtır. Ancak dikkat etmeniz gereken önemli bir nokta var: iki farklı rename implementasyonu mevcut ve bunların sözdizimi birbirinden oldukça farklı.

Perl tabanlı rename (rename.ul veya prename): Debian, Ubuntu ve türevi dağıtımlarda varsayılan olarak gelen sürüm. Perl düzenli ifadelerini destekler ve çok daha esnektir.

util-linux rename: Red Hat, CentOS, Fedora gibi RPM tabanlı dağıtımlarda yaygın olan, daha basit bir sözdizimi kullanan sürüm.

Hangi sürüme sahip olduğunuzu anlamak için şunu çalıştırın:

rename --version
# veya
file $(which rename)

Eğer çıktıda “Perl” ifadesi görüyorsanız Perl tabanlı sürümü kullanıyorsunuz demektir. Bu yazıda önce Perl tabanlı rename komutunu, ardından util-linux sürümünü, son olarak da bash döngüleriyle yapılan çözümleri inceleyeceğiz.

Perl Tabanlı rename Kullanımı

Temel Sözdizimi

rename [seçenekler] 's/eski_desen/yeni_desen/' dosyalar

Buradaki s/eski/yeni/ ifadesi Perl’in substitution (değiştirme) operatörüdür. Sol tarafa aranacak desen, sağ tarafa yazılacak yeni değer gelir.

İlk Örnek: Uzantı Değiştirme

Bir web projesinde tüm .htm dosyalarını .html yapmak istiyorsunuz:

# Önce ne yapacağını görmek için -n (dry-run) ile test edin
rename -n 's/.htm$/.html/' *.htm

# Çıktı doğruysa gerçekten çalıştırın
rename 's/.htm$/.html/' *.htm

Burada $ karakteri satır sonunu temsil eder, yani sadece dosya adının sonundaki .htm değiştirilir. . ile nokta karakterini escape ediyoruz çünkü düzenli ifadelerde nokta herhangi bir karakteri temsil eder.

-n parametresi: Komutu gerçekten çalıştırmadan simüle eder, ne değişeceğini gösterir. Her zaman önce bunu kullanın!

-v parametresi: Verbose mod, yapılan her değişikliği ekrana yazdırır.

Büyük-Küçük Harf Dönüşümleri

Fotoğraf makinelerinin ürettiği .JPG uzantılı dosyaları .jpg yapmak çok yaygın bir ihtiyaçtır:

rename 's/.JPG$/.jpg/' *.JPG

Peki ya dosya adlarının tamamını küçük harfe çevirmek isterseniz? Perl’in lc fonksiyonunu kullanabilirsiniz:

rename 'y/A-Z/a-z/' *
# veya
rename 's/(.+)/L$1/' *

Büyük harfe çevirmek için:

rename 's/(.+)/U$1/' *

Boşlukları Değiştirme

Dosya isimlerindeki boşluklar script yazarken baş ağrısına dönüşür. Hepsini alt çizgiyle değiştirmek için:

rename 's/ /_/g' *

Buradaki /g flag’i “global” anlamına gelir, sadece ilk eşleşmeyi değil tüm eşleşmeleri değiştirir.

Önek ve Sonek Ekleme

Bir backup scriptinden gelen dosyaları işaretlemek için başlarına backup_ eklemek istiyorsunuz:

rename 's/^/backup_/' *.sql

Dosya adlarının sonuna tarih eklemek isterseniz (uzantıdan önce):

rename 's/.sql$/_20240115.sql/' *.sql

Karmaşık Desen Eşleştirme

Diyelim ki report_2023_01_monthly.pdf, report_2023_02_monthly.pdf gibi dosyalarınız var ve bunları monthly_report_2023_01.pdf formatına çevirmek istiyorsunuz. Yakalama gruplarıyla bunu kolayca yapabilirsiniz:

rename 's/report_(d{4})_(d{2})_monthly/monthly_report_$1_$2/' *.pdf

Burada (d{4}) dört haneli sayıyı yakalar ve $1 ile geri çağırıyoruz. Parantezler yakalama grubu oluşturur.

util-linux rename Kullanımı

CentOS veya RHEL üzerinde çalışıyorsanız büyük ihtimalle bu sürümle karşılaşırsınız. Sözdizimi daha basittir ama düzenli ifade desteği sınırlıdır.

rename eski_string yeni_string dosyalar
# .conf dosyalarını .conf.bak yapmak
rename .conf .conf.bak /etc/nginx/*.conf

# Dosya adlarındaki "test" kelimesini "prod" ile değiştirmek
rename test prod test_*.sh

Bu sürümde Perl düzenli ifadeleri çalışmaz. Sadece sabit string değiştirme yapabilirsiniz. Daha karmaşık işlemler için bash döngülerine geçmek gerekir.

Bash Döngüsüyle Toplu Yeniden Adlandırma

Bash döngüleri rename komutunun yapamadığı ya da zorlandığı durumlarda devreye girer. Daha fazla kontrol imkanı sunar ve her dağıtımda aynı şekilde çalışır.

Temel for Döngüsü Yapısı

for dosya in *.txt; do
    yeni_isim="${dosya%.txt}.log"
    mv "$dosya" "$yeni_isim"
    echo "$dosya -> $yeni_isim"
done

Burada ${dosya%.txt} ifadesi parametrik genişletmeyle dosya adından .txt uzantısını çıkarır. Bu bash’ın yerleşik string manipülasyon özelliğidir.

Parametrik Genişletme Teknikleri

Bash’ta dosya adlarıyla çalışırken bilmeniz gereken temel parametrik genişletme ifadeleri:

  • ${degisken%sonek}: Sondan kısa eşleşmeyi kaldır
  • ${degisken%%sonek}: Sondan uzun eşleşmeyi kaldır
  • ${degisken#onek}: Baştan kısa eşleşmeyi kaldır
  • ${degisken##onek}: Baştan uzun eşleşmeyi kaldır
  • ${degisken/eski/yeni}: İlk eşleşmeyi değiştir
  • ${degisken//eski/yeni}: Tüm eşleşmeleri değiştir

Gerçek Dünya Senaryosu 1: Log Dosyalarını Arşivleme

Bir production sunucusunda nginx log dosyaları şu formatta birikiyor: access.log.1, access.log.2, error.log.1 gibi. Bunları tarihli bir arşiv klasörüne taşıyacak ve isimlendirmeyi düzenleyeceksiniz:

#!/bin/bash

ARSIV_DIR="/var/log/nginx/arsiv/$(date +%Y%m)"
mkdir -p "$ARSIV_DIR"

for dosya in /var/log/nginx/*.log.[0-9]*; do
    # Dosya adını ve numarasını ayır
    temel=$(basename "$dosya")
    isim="${temel%.*}"   # access.log
    numara="${temel##*.}" # 1, 2, 3...
    
    yeni_isim="${isim}_$(date +%Y%m%d)_${numara}.log"
    
    mv "$dosya" "${ARSIV_DIR}/${yeni_isim}"
    echo "Taşındı: $temel -> $yeni_isim"
done

echo "Arşivleme tamamlandı: $ARSIV_DIR"

Gerçek Dünya Senaryosu 2: Fotoğraf Koleksiyonunu Organize Etme

Farklı kaynaklardan gelen fotoğraflar karışık bir isim formatına sahip. EXIF verisini kullanarak yeniden adlandırma yapmak istiyorsunuz ama basit bir versiyon için dosya değiştirme tarihini kullanabiliriz:

#!/bin/bash

HEDEF_DIR="./organize_fotograflar"
mkdir -p "$HEDEF_DIR"

sayac=1

for foto in *.jpg *.JPG *.jpeg *.JPEG; do
    # Dosya var mı kontrol et (glob eşleşmezse)
    [ -f "$foto" ] || continue
    
    # Değiştirme tarihini al
    tarih=$(stat -c %y "$foto" | cut -d' ' -f1 | tr -d '-')
    
    # Yeni isim oluştur
    yeni_isim="foto_${tarih}_$(printf '%04d' $sayac).jpg"
    
    cp "$foto" "${HEDEF_DIR}/${yeni_isim}"
    echo "$foto -> $yeni_isim"
    
    ((sayac++))
done

while Döngüsü ile find Kombinasyonu

for döngüsü yüzlerce dosyada ARG_MAX limitine takılabilir. Bu durumda find ile while kombinasyonu daha güvenlidir:

find /proje/dokumanlari -name "*.txt" -type f | while read -r dosya; do
    dizin=$(dirname "$dosya")
    isim=$(basename "$dosya" .txt)
    mv "$dosya" "${dizin}/${isim}.md"
    echo "Dönüştürüldü: $dosya"
done

Dikkat: while döngüsü pipe içinde çalıştığında alt shell’de çalışır, değişkenler dışarıya aktarılmaz. Bunu aşmak için:

while IFS= read -r -d '' dosya; do
    dizin=$(dirname "$dosya")
    isim=$(basename "$dosya" .txt)
    mv "$dosya" "${dizin}/${isim}.md"
done < <(find /proje -name "*.txt" -type f -print0)

-print0 ve -d '' kombinasyonu dosya adlarında boşluk veya özel karakter olsa bile doğru çalışmasını sağlar.

Sıralı Numaralandırma

Bir müzik koleksiyonundaki dosyaları albüm sırasına göre numaralandırmak istiyorsunuz:

#!/bin/bash

sayac=1

for sarki in *.mp3; do
    [ -f "$sarki" ] || continue
    
    # Varsa mevcut numara önekini kaldır
    temiz_isim=$(echo "$sarki" | sed 's/^[0-9]*[_-]*//')
    
    # Yeni numaralı isim
    yeni_isim="$(printf '%02d' $sayac)_${temiz_isim}"
    
    mv "$sarki" "$yeni_isim"
    echo "$sarki -> $yeni_isim"
    
    ((sayac++))
done

Güvenli Çalışma Pratiği

Toplu değiştirme işlemlerinde bir hata geri dönüşü olmayabilir. Birkaç temel güvenlik pratiği:

Her Zaman Dry-Run Yapın

# rename için
rename -n 's/eski/yeni/' *

# bash döngüsü için, mv yerine echo kullanın
for dosya in *.log; do
    yeni="${dosya%.log}.txt"
    echo "mv "$dosya" "$yeni""
done

Backup Script Örneği

Değişiklik yapmadan önce dosya listesini kaydedin:

#!/bin/bash

# Önce mevcut durumu kaydet
ls -la > dosya_listesi_oncesi.txt

# Değişiklikleri yap
rename 's/pattern/replacement/' *.dosya

# Sonraki durumu kaydet
ls -la > dosya_listesi_sonrasi.txt

# Farkı göster
diff dosya_listesi_oncesi.txt dosya_listesi_sonrasi.txt

Çakışma Kontrolü

Hedef dosya adı zaten varsa ne olacağını düşünmek gerekir:

for dosya in *.txt; do
    yeni="${dosya%.txt}.md"
    
    if [ -e "$yeni" ]; then
        echo "UYARI: $yeni zaten mevcut, atlanıyor: $dosya"
        continue
    fi
    
    mv "$dosya" "$yeni"
    echo "OK: $dosya -> $yeni"
done

mmv ve diğer Alternatifler

mmv (multiple move) komutu bazı senaryolarda çok kullanışlıdır:

# Önce kurulum
sudo apt install mmv

# Kullanım
mmv '*.txt' '#1.md'
mmv 'rapor_*_*.pdf' 'arsiv_#1_#2.pdf'

Burada * joker karakterlerle eşleşen kısımlar #1, #2 ile geri çağrılır.

Pratik Kullanım Örnekleri Özeti

Sık karşılaşılan durumlar için hazır çözümler:

# Tüm dosyaları küçük harfe çevir
rename 's/(.+)/L$1/' *

# Noktalı virgülleri tire ile değiştir
rename 's/;/-/g' *

# Tarih formatını değiştir: 2024-01-15 -> 20240115
rename 's/(d{4})-(d{2})-(d{2})/$1$2$3/g' *

# Birden fazla boşluğu tek alt çizgiye indir
for f in *; do mv "$f" "$(echo "$f" | tr -s ' ' '_')"; done

# Sadece dizin içindeki dosyaları yeniden adlandır (alt dizinler hariç)
for f in *; do
    [ -f "$f" ] || continue
    mv "$f" "prefix_$f"
done

Sonuç

Dosya ismi toplu değiştirme işlemleri, her sistem yöneticisinin günlük hayatında mutlaka karşılaştığı görevler arasındadır. rename komutu Perl düzenli ifadeleriyle birleşince son derece güçlü bir araç haline gelir. Bash döngüleri ise daha fazla mantık ve kontrol gerektiren durumlarda vazgeçilmez olur.

Genel tavsiyem şu olur: Basit string değiştirme ve uzantı değişikliği gibi işlemler için rename yeterlidir ve hızlıdır. Koşullu mantık, dış komutların çıktısını kullanma, hata kontrolü veya taşıma/kopyalama kombinasyonu gerekiyorsa bash döngüsüne geçin.

En önemli alışkanlık ise her zaman rename -n ya da echo ile dry-run yapmak. Yüzlerce dosyayı bir anda silinen bir sysadmin hikayesi duymak istemiyorsunuz, yaşamak hiç istemiyorsunuz. Test et, doğrula, sonra uygula.

Yorum yapın