Arşiv İçindeki Dosyaları Değiştirmeden Güncelleme: tar ve zip ile Yerinde Dosya Güncelleme

Bir production sunucusunda çalışan bir uygulamanın konfigürasyon dosyasını güncellemek gerekiyor, ama konfigürasyon bir arşiv içinde. Arşivi açıp, dosyayı değiştirip, tekrar sıkıştırmak… Bu döngüyü kaç kez yaşadınız? Aslında hem tar hem de zip bu işi çok daha temiz bir şekilde yapmanıza izin veriyor. Bu yazıda, arşivleri tamamen çıkartmadan içindeki belirli dosyaları nasıl güncelleyeceğinizi, ekleyeceğinizi ve yöneteceğinizi ele alacağız.

Neden Bu Önemli?

Günlük sistem yönetimi rutininde arşivlerle çalışmak kaçınılmaz. Backup arşivleri, uygulama paketleri, konfigürasyon bundle’ları… Bunları her değişiklik için tamamen açıp tekrar sıkıştırmak hem zaman kaybı hem de disk I/O açısından gereksiz bir yük. Özellikle büyük arşivlerle çalışırken bu fark dramatik hale geliyor.

Bir örnek verelim: 50 GB’lık bir backup arşivinin içindeki tek bir konfigürasyon dosyasını güncellemek için arşivi tamamen açmanız gerekirse, hem 50 GB ekstra disk alanına ihtiyaç duyarsınız hem de işlem saatler sürebilir. Oysa yerinde güncelleme teknikleriyle bu işi dakikalar içinde, ek disk alanı kullanmadan tamamlayabilirsiniz.

tar ile Yerinde Güncelleme

tar aracı çoğu sysadmin tarafından sadece arşiv oluşturma ve açma için kullanılıyor. Ama --update, --append ve --delete gibi parametreler çok daha güçlü iş akışları sağlıyor.

Mevcut Dosyayı Güncelleme: –update Parametresi

--update veya kısa haliyle -u parametresi, yerel dosya arşivdeki versiyondan daha yeniyse otomatik olarak güncelleme yapar. Bu, timestamp karşılaştırması üzerinden çalışır.

# Temel kullanım
tar -uvf arsiv.tar yeni_konfig.conf

# Verbose çıktıyla güncelleme durumunu görmek için
tar -uvvf arsiv.tar config/app.conf

# Tam yol belirterek güncelleme
tar -uvf backup.tar ./etc/nginx/nginx.conf

Burada dikkat edilmesi gereken kritik nokta: --update sadece sıkıştırılmamış tar dosyalarında (.tar) çalışır. .tar.gz veya .tar.bz2 gibi sıkıştırılmış arşivlerde bu parametre işe yaramaz. Neden? Çünkü gzip ve bzip2 sıkıştırması, arşivin rastgele erişimine izin vermez; dosyanın başından sonuna kadar sıralı okunması gerekir.

Dosya Ekleme: –append Parametresi

--append veya -r, arşive yeni dosya ekler. Timestamp kontrolü yapmaz, doğrudan ekler.

# Tek dosya ekleme
tar -rvf arsiv.tar yeni_dosya.txt

# Birden fazla dosya ekleme
tar -rvf arsiv.tar dosya1.conf dosya2.conf dosya3.sh

# Tüm bir dizini arşive ekleme
tar -rvf arsiv.tar ./yeni_modul/

# Belirli uzantıdaki dosyaları ekleme
tar -rvf arsiv.tar $(find . -name "*.conf" -newer arsiv.tar)

Bu son örnekte find komutunu newer parametresiyle kullanmak, arşiv oluşturulduktan sonra değiştirilen tüm konfigürasyon dosyalarını bulup arşive ekliyor. Incremental backup senaryolarında bu kombinasyon oldukça kullanışlı.

Dosya Silme: –delete Parametresi

Arşivden belirli dosyaları kaldırmak için --delete kullanılır. Bu da yalnızca sıkıştırılmamış tar arşivlerinde çalışır.

# Arşivden dosya silme
tar --delete -f arsiv.tar eski_konfig.conf

# Dizin silme
tar --delete -f arsiv.tar ./eski_modul/

# Önce arşiv içeriğini listele, sonra sil
tar -tvf arsiv.tar | grep "eski"
tar --delete -f arsiv.tar ./eski/gereksiz_dosya.log

Önemli uyarı: --delete işlemi, arşivi yeniden oluşturur. Küçük dosyalar için hızlı olsa da büyük arşivlerde bu işlem yine de zaman alabilir.

Gerçek Dünya Senaryosu: Konfigürasyon Bundle Yönetimi

Diyelim ki uygulama deploymentlarınızda konfigürasyon dosyalarını bir tar bundle olarak taşıyorsunuz. Her deployment’ta sadece değişen konfig dosyalarını güncellemeniz gerekiyor.

#!/bin/bash
# konfig_guncelle.sh

ARSIV="app_config_bundle.tar"
KONFIG_DIR="./configs"
DEGISEN_DOSYALAR=$(find $KONFIG_DIR -newer $ARSIV -type f)

if [ -z "$DEGISEN_DOSYALAR" ]; then
    echo "Güncellenecek konfigürasyon yok."
    exit 0
fi

echo "Güncellenecek dosyalar:"
echo "$DEGISEN_DOSYALAR"

# Arşivi yedekle
cp $ARSIV "${ARSIV}.bak"

# Değişen dosyaları güncelle
tar -uvf $ARSIV $DEGISEN_DOSYALAR

echo "Güncelleme tamamlandı."
tar -tvf $ARSIV | sort

Bu script production ortamında çok işe yarıyor. Arşivi yedekledikten sonra güncelleme yapıyor ve son durumu listeyip doğrulama imkânı sunuyor.

zip ile Yerinde Güncelleme

zip bu konuda tar‘dan çok daha yetenekli. Çünkü ZIP formatı, dosyaların rastgele erişimine izin veren bir yapıya sahip. Arşivin sonunda bir “central directory” tutulur, bu sayede tek tek dosyalara erişmek mümkün.

Temel zip Güncelleme Komutları

# Arşivdeki dosyayı güncelle (sadece yerel dosya daha yeniyse)
zip -u arsiv.zip degisen_dosya.conf

# Güncelleme yoksa uyar, varsa uygula
zip -u -v arsiv.zip config/database.yml

# Birden fazla dosya güncelle
zip -u arsiv.zip dosya1.conf dosya2.conf

# Taze mod: timestamp'e bakmaksızın zorla güncelle
zip -f arsiv.zip hedef_dosya.sh

-u ile -f arasındaki farka dikkat edin. -u (update) timestamp kontrolü yapar ve sadece yerel dosya daha yeniyse günceller. -f (freshen) ise arşivde zaten var olan dosyaları timestamp’e bakılmaksızın günceller ama yeni dosya eklemez. -u ise hem günceller hem yeni dosya ekler.

Arşivden Dosya Silme

# Tek dosya silme
zip -d arsiv.zip gereksiz_dosya.txt

# Pattern ile silme
zip -d arsiv.zip "*.log"
zip -d arsiv.zip "temp/*"

# Belirli dizini silme
zip -d arsiv.zip "eski_modul/*"

# Silinen dosyaları görmek için verbose
zip -dv arsiv.zip "*.tmp"

Pattern kullanırken tırnak işaretlerine dikkat edin. Tırnak olmazsa shell glob expansion devreye girer ve beklenmedik sonuçlar çıkabilir.

zip ile İçerik Listeleme ve Doğrulama

Güncelleme öncesi ve sonrası arşiv içeriğini kontrol etmek önemli:

# Arşiv içeriğini listele
zipinfo arsiv.zip

# Sadece dosya isimlerini listele
zipinfo -1 arsiv.zip

# Belirli dosyayı ara
zipinfo arsiv.zip | grep "konfig"

# Arşiv bütünlüğünü test et
zip -T arsiv.zip

# Detaylı test
unzip -t arsiv.zip

Gerçek Dünya Senaryosu: Java/WAR Dosyası Güncelleme

Java uygulamalarında .war dosyaları aslında birer ZIP arşividir. Tüm uygulamayı yeniden derlemek yerine, sadece değişen property dosyasını WAR içinde güncellemek mümkün:

#!/bin/bash
# war_konfig_guncelle.sh

WAR_DOSYASI="/opt/tomcat/webapps/uygulama.war"
YENI_KONFIG="./application.properties"
WAR_ICINDEKI_YOL="WEB-INF/classes/application.properties"

# Önce mevcut durumu yedekle
cp $WAR_DOSYASI "${WAR_DOSYASI}.$(date +%Y%m%d_%H%M%S).bak"

# Güncellemeyi yap
# Önce geçici dizine çıkart, yolu düzenle
mkdir -p /tmp/war_update/WEB-INF/classes/
cp $YENI_KONFIG /tmp/war_update/WEB-INF/classes/

cd /tmp/war_update
zip -u $WAR_DOSYASI WEB-INF/classes/application.properties

# Temizle
cd -
rm -rf /tmp/war_update

echo "WAR güncellendi. İçerik doğrulanıyor..."
unzip -p $WAR_DOSYASI WEB-INF/classes/application.properties | head -20

Bu yaklaşım, özellikle Tomcat veya JBoss gibi uygulama sunucularında hotdeploy senaryolarında çok işe yarıyor. Tüm uygulamayı yeniden deploy etmek yerine sadece konfigürasyonu güncelleyip servisi reload edebiliyorsunuz.

Sıkıştırılmış tar Arşivlerinde Dosya Güncelleme

Daha önce belirttiğim gibi, .tar.gz gibi sıkıştırılmış arşivler doğrudan güncellemeye izin vermiyor. Ama geçici dosya kullanarak bu işi yine de verimli şekilde yapabilirsiniz.

#!/bin/bash
# sikilmis_arsiv_guncelle.sh

ARSIV="backup.tar.gz"
GUNCELLENECEK_DOSYA="etc/app/config.conf"
YENI_DOSYA="./config.conf"

# Geçici dizin oluştur
TEMP_DIR=$(mktemp -d)

echo "Arşiv açılıyor..."
tar -xzf $ARSIV -C $TEMP_DIR

echo "Dosya güncelleniyor..."
cp $YENI_DOSYA "$TEMP_DIR/$GUNCELLENECEK_DOSYA"

echo "Arşiv yeniden oluşturuluyor..."
cd $TEMP_DIR
tar -czf "/tmp/yeni_$ARSIV" .
cd -

# Orijinali yedekle ve yenisiyle değiştir
mv $ARSIV "${ARSIV}.bak"
mv "/tmp/yeni_$ARSIV" $ARSIV

# Temizle
rm -rf $TEMP_DIR

echo "İşlem tamamlandı."

Bu yaklaşım zaruri olduğunda kullanılır. Büyük arşivlerde yine de zaman alacak, ama en azından süreç otomatize ve tekrarlanabilir.

İleri Seviye: Python zipfile ile Programatik Güncelleme

Bazen shell scriptlerin yetersiz kaldığı, daha karmaşık arşiv manipülasyonları gerekebilir. Python’un zipfile modülü bu gibi durumlarda kurtarıcı olabiliyor:

#!/usr/bin/env python3
# arsiv_guncelle.py

import zipfile
import shutil
import os
import sys
from datetime import datetime

def zip_dosyasini_guncelle(arsiv_yolu, kaynak_dosya, arsiv_icindeki_yol):
    """
    ZIP arşivindeki belirli bir dosyayı günceller.
    Bütünlüğü korumak için geçici dosya kullanır.
    """
    gecici_arsiv = arsiv_yolu + ".tmp"
    
    try:
        with zipfile.ZipFile(arsiv_yolu, 'r') as kaynak:
            with zipfile.ZipFile(gecici_arsiv, 'w', 
                                 compression=kaynak.compression) as hedef:
                # Mevcut dosyaları kopyala, güncellenecek dosyayı atla
                for item in kaynak.infolist():
                    if item.filename != arsiv_icindeki_yol:
                        hedef.writestr(item, kaynak.read(item.filename))
                
                # Yeni dosyayı ekle
                hedef.write(kaynak_dosya, arsiv_icindeki_yol)
        
        # Yedek al ve güncelle
        yedek_yolu = f"{arsiv_yolu}.{datetime.now().strftime('%Y%m%d_%H%M%S')}.bak"
        shutil.copy2(arsiv_yolu, yedek_yolu)
        shutil.move(gecici_arsiv, arsiv_yolu)
        
        print(f"Güncelleme başarılı: {arsiv_icindeki_yol}")
        print(f"Yedek: {yedek_yolu}")
        
    except Exception as e:
        # Hata durumunda geçici dosyayı temizle
        if os.path.exists(gecici_arsiv):
            os.remove(gecici_arsiv)
        raise e

if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("Kullanım: arsiv_guncelle.py <arsiv.zip> <kaynak_dosya> <arsiv_icindeki_yol>")
        sys.exit(1)
    
    zip_dosyasini_guncelle(sys.argv[1], sys.argv[2], sys.argv[3])

Bu script özellikle şu senaryolarda işe yarıyor: farklı compression level’larla oluşturulmuş arşivlerin bütünlüğünü koruyarak güncellenmesi gerektiğinde, veya güncelleme işlemini bir CI/CD pipeline’ına entegre etmeniz gerektiğinde.

Yaygın Hatalar ve Çözümleri

Arşiv güncelleme işlemlerinde karşılaşılan bazı tipik sorunlar ve bunların çözümleri:

Yanlış çalışma dizini: tar ve zip, dosya yollarını çalışma dizinine göre kaydeder. Güncelleme yaparken de aynı dizinden çalışmanız gerekir, aksi takdirde arşivde duplicate dosyalar oluşabilir.

# Yanlış: Farklı dizinden çalışmak
zip -u /backup/arsiv.zip /tmp/config.conf
# Arşivde hem "etc/config.conf" hem "tmp/config.conf" olabilir

# Doğru: Doğru dizinden çalışmak
cd /tmp
zip -u /backup/arsiv.zip config.conf

tar’da duplicate entries: tar -r veya tar -u ile güncelleme yaparken arşivde aynı dosyanın birden fazla kaydı oluşabilir. Bu teknik olarak geçerlidir (tar, arşivi açarken son versiyonu kullanır), ama arşiv boyutunu şişirebilir.

# Duplicate kontrol
tar -tvf arsiv.tar | awk '{print $NF}' | sort | uniq -d

# Arşivi yeniden oluşturarak duplicate'ları temizle
tar -cvf temiz_arsiv.tar $(tar -tvf arsiv.tar | awk '{print $NF}' | sort -u)

ZIP merkezi dizin bozulması: Bazı durumlarda (disk doluluğu, kesinti vb.) ZIP arşivinin central directory’si bozulabilir. Bu durumda güncelleme yapmadan önce arşivi onarmak gerekir.

# Bozuk ZIP'i onar
zip -FF bozuk_arsiv.zip --out onarilan_arsiv.zip

# Bütünlük testi
unzip -t onarilan_arsiv.zip

Performans İpuçları

Büyük arşivlerle çalışırken bazı pratik öneriler:

  • ionice kullanın: Disk yoğun işlemlerde sistem performansını korumak için ionice -c 3 zip -u buyuk_arsiv.zip dosya.conf şeklinde çalıştırın.
  • rsync benzeri yaklaşım: Çok sayıda küçük güncelleme yerine, değişiklikleri biriktirip toplu güncelleme yapın. Her güncelleme ZIP central directory’yi yeniden yazacağından, onlarca küçük güncelleme yerine bir toplu işlem daha verimlidir.
  • sıkıştırma seviyesi: Güncelleme sıklığı yüksek arşivler için düşük sıkıştırma seviyesi (zip -1) kullanmayı değerlendirin. Daha az CPU kullanır ve güncelleme hızlanır.
# Düşük sıkıştırmayla güncelleme (hız öncelikli)
zip -1 -u arsiv.zip hizli_degisen_konfig.conf

# Maksimum sıkıştırmayla güncelleme (boyut öncelikli)
zip -9 -u arsiv.zip nadiren_degisen_dosya.conf

Sonuç

Arşiv içindeki dosyaları yerinde güncellemek, hem disk alanı hem zaman açısından ciddi tasarruf sağlıyor. Özetlemek gerekirse:

  • Sıkıştırılmamış .tar dosyaları için tar -u (timestamp’e göre güncelle) ve tar -r (ekle) kullanın. Büyük arşivlerde bile verimli çalışır.
  • ZIP arşivleri için zip -u (güncelle ve ekle) veya zip -f (sadece mevcut olanları güncelle) tercih edin. ZIP formatının yapısı bu işlemler için idealdir.
  • Sıkıştırılmış .tar.gz, .tar.bz2 gibi arşivlerde doğrudan güncelleme mümkün değildir; geçici dizin yaklaşımı kullanın.
  • Üretim ortamında daima yedek alın ve işlem sonrası arşiv bütünlüğünü doğrulayın.
  • WAR, JAR, APK gibi ZIP tabanlı uygulama paketleri, zip komutları ile doğrudan güncellenebilir. Bu, özellikle hızlı konfigürasyon değişikliklerinde deployment sürecini önemli ölçüde kısaltır.

Bu teknikleri günlük rutininize dahil ettiğinizde, arşiv yönetimi konusundaki verimliliğinizin belirgin şekilde arttığını göreceksiniz. Bir dahaki sefere 50 GB’lık bir arşivi açmak üzere olduğunuzda, önce bu yöntemlerden birinin işi halledip halledemeyeceğini düşünün.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir