xargs ile Komutları Toplu Çalıştırma

Terminal açıksın, yapacakların listesi uzun ve her dosya, her kullanıcı, her servis için ayrı ayrı komut yazmak can sıkıcı bir hal almaya başladı. İşte tam bu noktada xargs devreye giriyor. Belki daha önce bir yerde gördün, geçiştirdin. Belki “find ile pipe yeter” dedin. Ama xargs öğrendikten sonra terminal alışkanlıklarının ne kadar değiştiğini göreceksin.

xargs Nedir ve Neden Lazım?

xargs, standart girdiden (stdin) aldığı verileri başka bir komuta argüman olarak ileten bir araç. Kulağa basit geliyor ama pratikte inanılmaz güçlü. Çoğu Linux komutu büyük argüman listelerini doğrudan kabul etmez ya da pipe ile gelen veriyi işleyemez. xargs bu ikisi arasındaki köprüyü kuruyor.

Klasik pipe kullanımında sol taraftaki komutun çıktısı, sağ taraftaki komutun stdin‘ine gidiyor. Ama bazı komutlar stdin’den okumak yerine argüman listesi bekliyor. Örneğin rm komutu, dosya adlarını argüman olarak alıyor. Ona echo "dosya.txt" | rm yapamazsın, çalışmaz. Ama echo "dosya.txt" | xargs rm mükemmel çalışır.

Bir de şöyle düşün: Binlerce dosyayı silmek istiyorsun. Tek seferde rm * yapsan “Argument list too long” hatasıyla karşılaşabilirsin. xargs burada devreye giriyor ve argümanları parçalara bölerek işliyor.

Temel Kullanım

En sade haliyle xargs şöyle çalışır:

echo "dosya1.txt dosya2.txt dosya3.txt" | xargs rm

Bu komut, echo’nun çıktısını alıp rm dosya1.txt dosya2.txt dosya3.txt şeklinde çalıştırır. Basit ama etkili.

Bir de şu örneğe bak:

cat silinecek_dosyalar.txt | xargs rm -f

silinecek_dosyalar.txt içindeki her satırdaki dosyayı siler. Operasyonel açıdan çok işe yarayan bir pattern bu. Log temizleme scriptlerinde, geçici dosya yönetiminde sıkça kullanırsın.

Önemli Parametreler

xargs‘ın davranışını şekillendiren birkaç kritik parametre var:

  • -n [sayı]: Her komut çalıştırmasında kaç argüman kullanılacağını belirler. xargs -n 1 her argüman için ayrı komut çalıştırır.
  • -I [yer_tutucu]: Argümanın komut içinde tam olarak nereye yerleştirileceğini belirtir. En çok {} kullanılır.
  • -P [sayı]: Paralel çalıştırma. Aynı anda kaç işlem başlatılacağını belirler.
  • -d [ayraç]: Argümanları ayırmak için kullanılacak karakteri belirtir. Varsayılan boşluk ve yeni satır.
  • -0: Null karakter ile ayrılmış girdi bekler. find -print0 ile birlikte kullanılır.
  • -t: Çalıştırılan komutu ekrana basar (debug için harika).
  • -p: Her komut için onay ister. Kritik işlemler öncesi kullanışlı.
  • –max-args: -n ile aynı işlevi görür, uzun format versiyonu.
  • -r: Girdi boşsa komut çalıştırmaz. GNU xargs’a özgü, macOS’ta dikkat.

find ile xargs: Klasik Kombinasyon

Sysadmin işlerinin büyük bölümü find | xargs kombinasyonuyla çözülür. Bu ikilinin gücünü birkaç gerçek senaryo üzerinden görelim.

30 Günden Eski Log Dosyalarını Temizlemek

Prodüksiyon sunucularında log dizinleri zamanla şişer. Şu komut, 30 günden eski .log uzantılı dosyaları bulup siler:

find /var/log/uygulama -name "*.log" -mtime +30 -print0 | xargs -0 rm -f

Burada -print0 ve -0 ikilisi kritik. Dosya adlarında boşluk, özel karakter olabilir. Normal pipe kullansan, boşluklu dosya adı iki ayrı argüman olarak yorumlanır. print0 null karakter kullanır, xargs -0 da null karakter bekler. Bu kombinasyon güvenli ve sağlam çalışır.

Belirli Uzantılı Dosyalarda İzin Değiştirmek

Web sunucusuna yeni dosyalar atıldı ve hepsinin izinleri yanlış geldi. Tüm PHP dosyalarını bulmak ve doğru izni vermek için:

find /var/www/html -name "*.php" -type f -print0 | xargs -0 chmod 644

Script dosyalarını yürütülebilir yapmak için de aynı mantık:

find /opt/scripts -name "*.sh" -type f -print0 | xargs -0 chmod +x

-I Parametresi ile Argüman Yerleştirme

-I {} kullanımı, argümanın komut içinde tam olarak nereye gireceğini kontrol etmeni sağlar. Bu özellikle argümanın başa, ortaya ya da farklı yerlere gitmesi gerektiğinde şart.

find /backup -name "*.tar.gz" -print0 | xargs -0 -I {} mv {} /archive/

Bu komut, bulduğu her .tar.gz dosyasını /archive/ dizinine taşır. {} placeholder’ı, bulunan her dosya adıyla değiştirilir.

Bir başka örnek: Birden fazla sunucuya SSH ile bağlanıp disk durumunu kontrol etmek istiyorsun. Sunucu listesi bir dosyada:

cat sunucular.txt | xargs -I {} ssh admin@{} "df -h / | tail -1"

Bu komut her sunucuya sırayla bağlanır ve disk kullanım bilgisini getirir. Basit bir monitoring scripti için güzel bir başlangıç noktası.

Paralel Çalıştırma ile Hız Kazanmak

xargs -P parametresi en az bilinip en çok işe yarayan özelliklerden biri. Çok sayıda dosyayı işliyorsan, paralel çalıştırmayla ciddi zaman kazanabilirsin.

Diyelim ki yüzlerce resim dosyasını sıkıştırman gerekiyor:

find /data/images -name "*.png" -print0 | xargs -0 -P 8 -I {} convert {} -quality 85 {}.jpg

-P 8 ile aynı anda 8 dönüştürme işlemi paralel çalışır. Sunucunda kaç çekirdek varsa ona göre ayarlarsın. Genel kural: çekirdek sayısına eşit ya da bir fazlası iyi bir başlangıç noktası.

Başka bir örnek: Bir dizindeki tüm log dosyalarını gzip ile sıkıştırmak:

find /var/log/archive -name "*.log" -type f -print0 | xargs -0 -P 4 gzip

4 dosyayı aynı anda sıkıştırır. Binlerce dosyayla çalışıyorsan bu fark çok büyük oluyor.

Gerçek Dünya Senaryosu: Toplu Kullanıcı İşlemleri

Bir şirkette yeni bir proje başladı ve 50 kullanıcının belirli bir gruba eklenmesi gerekiyor. Kullanıcı adları bir CSV’den geliyor:

cut -d',' -f1 yeni_kullanicilar.csv | xargs -I {} usermod -aG proje_grubu {}

Ya da ters yönden: Ayrılan çalışanların hesaplarını devre dışı bırakmak:

cat ayrilanlar.txt | xargs -I {} usermod -L {}

usermod -L hesabı kilitler, siler değil. Güvenli taraf bu.

Bir adım daha ileri: Hesapları kilitle ve home dizinlerini arşivle:

cat ayrilanlar.txt | xargs -I {} bash -c 'usermod -L {} && tar -czf /backup/users/{}.tar.gz /home/{}'

Birden fazla komut çalıştırmak istediğinde bash -c '...' yapısını kullan. Bu xargs‘ın en güçlü kullanım biçimlerinden biri.

-n Parametresi ile Toplu İşlemi Kontrol Etmek

Bazen argümanları belirli gruplar halinde işlemek istersin. -n parametresi bunu sağlar.

Üç argümanı aynı anda işle:

echo "a b c d e f" | xargs -n 3 echo

Çıktı şu şekilde olur:

a b c
d e f

Pratik kullanım örneği: Veritabanı yedeklerini gruplar halinde rsync ile aktarmak:

ls /backup/db/*.sql | xargs -n 5 -I {} rsync -av {} user@backup-server:/remote/backup/

Her seferinde 5 dosyayı aktarır, sonra bir sonraki gruba geçer.

Boşluklu Dosya Adlarıyla Güvenli Çalışmak

Bu konu önemli çünkü birçok kişi burada hata yapıyor. Türkçe karakter, boşluk ya da özel karakter içeren dosya adları normal pipe kullanımında sorun çıkarır.

Kötü örnek (boşluklu adlarda bozulur):

find /data -name "*.txt" | xargs rm

İyi örnek (her zaman güvenli):

find /data -name "*.txt" -print0 | xargs -0 rm

Test edelim. Önce test dosyaları oluştur:

touch "dosya bir.txt" "dosya iki.txt" "dosya üç.txt"
find . -name "*.txt" -print0 | xargs -0 ls -la

Bu şekilde çalışır ve tüm dosyaları doğru şekilde listeler.

-t ve -p Parametreleri: Debug ve Güvenlik

Özellikle kritik işlemler öncesinde bu iki parametre çok değerli.

-t parametresi çalıştırılacak komutu önce ekrana basar:

find /tmp -name "*.tmp" -print0 | xargs -0 -t rm -f

Her rm çalıştırılmadan önce tam komut görüntülenir. Neyin silineceğini görmek istediğinde kullanışlı.

-p parametresi her adımda onay ister:

find /etc -name "*.conf" -print0 | xargs -0 -p chmod 640

Her dosya için “chmod 640 /etc/dosya.conf?…” sorusunu sorar. Evet ya da hayır yazarsın. Emin olmadığın değişikliklerde ya da öğrenme aşamasında çok işe yarıyor.

grep ile xargs: Metin Arama ve İşlem

Başka bir güçlü kombinasyon: Belirli bir pattern içeren dosyaları bul, sonra işlem yap.

Tüm config dosyalarında eski bir IP adresini bul:

grep -rl "192.168.1.100" /etc/ | xargs -I {} sed -i 's/192.168.1.100/10.0.0.100/g' {}

grep -r recursive arama yapar, -l sadece dosya adlarını listeler. xargs bu dosyaları alıp sed ile içlerindeki IP’yi değiştirir. Tek komut, tüm config dosyaları güncellendi.

Dikkat: sed -i doğrudan dosyayı değiştirir. Önce -t ile test et ya da yedek al:

grep -rl "eski_deger" /etc/ | xargs -I {} cp {} {}.bak
grep -rl "eski_deger" /etc/ | xargs -I {} sed -i 's/eski_deger/yeni_deger/g' {}

Gerçek Senaryo: Sunucu Envanter Scripti

Elinde 20 sunucu var, hepsinin OS versiyonunu, uptime’ını ve disk durumunu toplamak istiyorsun. Basit ama etkili:

cat /etc/hosts | grep "web-" | awk '{print $2}' | xargs -P 10 -I {} bash -c 
  'echo "=== {} ==="; ssh -o ConnectTimeout=5 admin@{} "cat /etc/os-release | grep PRETTY_NAME; uptime; df -h /" 2>/dev/null || echo "{} ERIŞILEMEZ"'

-P 10 ile 10 sunucuya paralel bağlanıyor. ConnectTimeout=5 ile bağlantı 5 saniyede cevap vermezse geçiyor. Erişilemeyen sunucular “ERİŞİLEMEZ” olarak işaretleniyor.

Aynı şeyi daha temiz bir şekilde:

cat sunucu_listesi.txt | xargs -P 5 -I {} 
  sh -c 'result=$(ssh -o ConnectTimeout=3 {} "uptime" 2>&1); echo "{}: $result"'

Bu tür scriptler cron’a eklenip her sabah sonuçları bir dosyaya yazabilir. Basit monitoring çözümü.

Büyük Argüman Listesi Sorunu

Şu hatayı büyük ihtimalle gördün:

bash: /bin/rm: Argument list too long

Bu ARG_MAX sınırından kaynaklanıyor. Sistemin kabul ettiği maksimum argüman uzunluğunu aşıyorsun. xargs bu sorunu otomatik çözüyor:

# Bu hata verebilir (yüz binlerce dosya varsa)
rm /data/logs/*.log

# Bu her zaman çalışır
find /data/logs -name "*.log" | xargs rm -f

# Ya da direkt find ile
find /data/logs -name "*.log" -delete

xargs argüman listesini ARG_MAX sınırını geçmeyecek parçalara bölerek çalıştırır. Bunu senin yerine halleder.

Pratik Küçük Şeyler

Birkaç günlük kullanım senaryosu daha:

Boş dosyaları bul ve sil:

find /var/www -empty -type f -print0 | xargs -0 rm -f

Belirli boyutun üzerindeki dosyaları listele ve sahiplerini göster:

find /home -size +100M -print0 | xargs -0 ls -lah

Bir listedeki paketleri kur:

cat paket_listesi.txt | xargs apt-get install -y

Docker container’larını toplu sil (dikkatli kullan):

docker ps -aq --filter "status=exited" | xargs docker rm

Kullanılmayan Docker image’larını temizle:

docker images -q --filter "dangling=true" | xargs docker rmi

macOS ile GNU xargs Farkları

Eğer hem Linux hem macOS’ta çalışıyorsan bu kısım önemli. macOS’taki xargs BSD versiyonu, Linux’takinden farklı davranışlar gösterebilir.

En sık karşılaşılan fark: BSD xargs -r parametresini desteklemez. Boş girdi geldiğinde komut yine de çalışır.

macOS’ta GNU xargs kullanmak istersen:

brew install findutils
# Sonra gxargs olarak çağırırsın

Script yazıyorsan ve her iki platformda çalışmasını istiyorsan, en güvenli yol -print0 | xargs -0 kombinasyonunu kullanmak. Bu her iki platformda da sorunsuz çalışır.

Hata Ayıklama ve İpuçları

Bir xargs komutunu çalıştırmadan önce ne yapacağını görmek istiyorsan echo ile test et:

find /tmp -name "*.tmp" -print0 | xargs -0 echo rm -f

rm -f yerine echo rm -f koyarsın. Gerçek silme yapmaz, sadece çalışacak komutları ekrana basar. Bu alışkanlığı edinirsen kritik hataların önüne geçersin.

Çalışma hızını ölçmek için time kullan:

# Seri
time find /data -name "*.log" | xargs -n 1 gzip

# Paralel
time find /data -name "*.log" | xargs -P 4 -n 1 gzip

Farkı görmek motivasyon verici. Özellikle büyük dosya sayılarında paralel versiyon dramatik şekilde hızlı.

Sonuç

xargs ilk bakışta küçük bir araç gibi görünüyor ama sysadmin iş akışında oynadığı rol büyük. Toplu dosya işlemleri, çoklu sunucu yönetimi, paralel görev çalıştırma ve argüman listesi sorunlarının çözümünde bir numaralı silah.

Öğrenilmesi gereken birkaç temel nokta var: Dosya adlarında her zaman -print0 | xargs -0 kombinasyonunu kullan. Kritik işlemlerde önce -t ile ne yapacağını gör, sonra çalıştır. Paralel işlemlerde -P ile ciddi zaman kazanabilirsin. Ve bash -c '...' yapısıyla birden fazla komutu zincirlemeyi unutma.

Bunları bir kez içselleştirdin mi, terminal oturumlarında xargs olmadan bir şey eksik gibi hissedeceksin. En iyi öğrenme yöntemi test ortamında denemek. Bir dizin aç, içine dosyalar koy ve bu yazıdaki komutları tek tek çalıştır. Ellerin kirlenmeden xargs öğrenilmiyor.

Yorum yapın