Linux’ta join ve paste Komutları ile Dosyaları Birleştirme

Linux’ta metin işleme söz konusu olduğunda çoğu sysadmin aklına ilk olarak grep, awk veya sed gelir. Oysa join ve paste komutları, doğru senaryoda bu araçların tamamını geride bırakacak kadar güçlü ve pratik çözümler sunar. Özellikle log analizi, kullanıcı yönetimi ve sistem raporlama gibi günlük sysadmin görevlerinde bu iki komut hayat kurtarır. Gelin bu komutları hem teorik hem de gerçek dünya senaryolarıyla ele alalım.

paste Komutu: Satırları Yan Yana Getirmek

paste komutunun işi son derece basittir: birden fazla dosyanın satırlarını yan yana birleştirir. SQL’deki UNION yerine daha çok yatay birleştirmeye benzer. Varsayılan ayraç karakteri tab’dır ama bunu değiştirebilirsiniz.

Temel Kullanım

Elimizde şu iki dosya olduğunu düşünelim:

# sunucular.txt
web01
web02
db01
db02

# ip_adresleri.txt
192.168.1.10
192.168.1.11
192.168.1.20
192.168.1.21

Bu iki dosyayı yan yana birleştirmek için:

paste sunucular.txt ip_adresleri.txt

Çıktı şöyle olur:

web01   192.168.1.10
web02   192.168.1.11
db01    192.168.1.20
db02    192.168.1.21

Varsayılan ayraç tab karakteridir. Bunu değiştirmek için -d parametresini kullanırsınız:

paste -d ":" sunucular.txt ip_adresleri.txt
# web01:192.168.1.10
# web02:192.168.1.11

paste Parametreleri

  • -d: Ayraç karakterini belirler. Birden fazla karakter girerseniz dosyalar arasında sırayla kullanır
  • -s: Dosyaları sütun yerine satır olarak sıralı birleştirir, yani bir dosyanın tüm satırlarını tek satıra getirir
  • : Parametre sonunu belirtir, dosya adı tire ile başlıyorsa işe yarar

-s parametresi biraz kafa karıştırıcı olabilir, daha iyi anlamak için örnek görelim:

# aylar.txt dosyası
Ocak
Subat
Mart
Nisan

paste -s aylar.txt
# Ocak   Subat   Mart    Nisan

Bir dosyanın tüm satırlarını tek bir satırda, tab ile ayrılmış şekilde birleştirdi. Virgülle ayırmak isterseniz:

paste -s -d "," aylar.txt
# Ocak,Subat,Mart,Nisan

Bu özellik özellikle shell script yazarken bir diziyi tek satıra dökmek için çok kullanışlıdır.

Gerçek Dünya: Sunucu Envanter Raporu Oluşturmak

Diyelim ki monitoring sistemlerinizden farklı scriptler çalıştırıyorsunuz ve her biri ayrı bir dosyaya veri yazıyor. Bunu tek bir rapora dönüştürmek istiyorsunuz:

# hostname'leri al
hostname -s > /tmp/hostnames.txt

# CPU core sayısını al
nproc > /tmp/cpu_cores.txt

# RAM miktarını al (GB cinsinden)
free -g | awk 'NR==2{print $2}' > /tmp/ram_gb.txt

# Disk kullanımını al
df -h / | awk 'NR==2{print $5}' > /tmp/disk_usage.txt

# Hepsini birleştir
paste -d "," /tmp/hostnames.txt /tmp/cpu_cores.txt /tmp/ram_gb.txt /tmp/disk_usage.txt

Birden fazla sunucuda bu scripti çalıştırıp çıktıları birleştirdiğinizde elinizde güzel bir CSV raporu olur.

paste ile Stdin Kullanmak

paste komutu - karakteriyle stdin’den okuyabilir. Bu özellik pipe zincirlerinde çok işe yarar:

# Bir dizindeki dosya adlarını ve boyutlarını yan yana listele
ls /var/log/ > /tmp/dosya_adlari.txt
ls -s /var/log/ | awk 'NR>1{print $1}' > /tmp/dosya_boyutlari.txt
paste dosya_adlari.txt dosya_boyutlari.txt

Ya da doğrudan pipe ile:

# /etc/passwd dosyasından kullanıcı adı ve UID'yi yan yana getir
cut -d: -f1 /etc/passwd > /tmp/kullanici_adlari.txt
cut -d: -f3 /etc/passwd > /tmp/uid_listesi.txt
paste -d ":" kullanici_adlari.txt uid_listesi.txt

join Komutu: Ortak Alana Göre Birleştirme

join komutu, ilişkisel veritabanlarındaki JOIN işleminin komut satırı versiyonudur. İki dosyayı ortak bir alana göre birleştirir. Bu özelliği onu paste‘den çok daha güçlü kılar çünkü satır sırasına bağımlı değilsiniz, ortak bir anahtar üzerinden çalışırsınız.

Kritik nokta: join komutu, birleştirme yapacağı alan üzerinden sıralı dosyalar bekler. Sıralı olmayan dosyalarla çalışırsanız yanlış sonuçlar alırsınız.

Temel Kullanım

# kullanicilar.txt
alice 101
bob 102
charlie 103

# roller.txt
alice admin
bob developer
charlie ops
join kullanicilar.txt roller.txt
# alice 101 admin
# bob 102 developer
# charlie 103 ops

join varsayılan olarak her iki dosyadaki ilk alanı karşılaştırır ve eşleşen satırları birleştirir.

join Parametreleri

  • -1 N: Birinci dosyada N. alanı birleştirme anahtarı olarak kullan
  • -2 N: İkinci dosyada N. alanı birleştirme anahtarı olarak kullan
  • -t: Alan ayracını belirle
  • -a 1: Birinci dosyadaki eşleşmeyen satırları da dahil et (LEFT JOIN)
  • -a 2: İkinci dosyadaki eşleşmeyen satırları da dahil et (RIGHT JOIN)
  • -v 1: Sadece birinci dosyada eşleşmeyen satırları göster
  • -v 2: Sadece ikinci dosyada eşleşmeyen satırları göster
  • -i: Büyük/küçük harf duyarsız karşılaştırma
  • -o: Çıktı formatını belirle
  • -e: Eksik alanlar için kullanılacak string’i belirle

Farklı Alanlara Göre Birleştirme

Gerçek hayatta her zaman birinci alan ortak alan olmaz. Şu örneğe bakalım:

# servisler.txt (format: servis_adi port durum)
nginx 80 aktif
mysql 3306 aktif
redis 6379 aktif

# loglar.txt (format: tarih port istek_sayisi)
2024-01-15 80 15234
2024-01-15 3306 4521
2024-01-15 6379 8932

Burada servisler.txt’deki 2. alan ile loglar.txt’deki 2. alanı birleştirmek istiyoruz:

join -1 2 -2 2 servisler.txt loglar.txt

Dosyaları Sıralı Hale Getirmek

join için sıralama zorunluluğunu unutmamak gerekir. Bunu sort ile hallederiz:

# Önce her iki dosyayı birleştirme alanına göre sırala
sort -k1 kullanici_verileri.txt > /tmp/kullanici_sirali.txt
sort -k1 kullanici_rolleri.txt > /tmp/roller_sirali.txt

# Sonra join yap
join /tmp/kullanici_sirali.txt /tmp/roller_sirali.txt

Daha temiz bir yol olarak process substitution kullanabilirsiniz:

join <(sort -k1 kullanici_verileri.txt) <(sort -k1 kullanici_rolleri.txt)

LEFT JOIN ve Eksik Eşleşmeler

SQL’deki LEFT JOIN mantığını join -a ile uygulayabilirsiniz:

# aktif_sunucular.txt
web01
web02
web03
db01

# monitoring_kayitlari.txt
web01 OK
db01 CRITICAL
# Hangi sunucular monitoring'de yok?
join -a 1 -t " " <(sort aktif_sunucular.txt) <(sort monitoring_kayitlari.txt)

Çıktıda web02 ve web03 monitoring kaydı olmadan görünür. Bu boşlukları -e parametresiyle doldurabiliriz:

join -a 1 -e "EKSIK" -o 1.1,2.2 <(sort aktif_sunucular.txt) <(sort monitoring_kayitlari.txt)

Gerçek Dünya Senaryoları

Senaryo 1: Log Analizi ve Korelasyon

Bir web sunucusunda iki farklı log kaynağını birleştirmek istiyorsunuz. Nginx access log’undan IP bazlı istek sayısını çıkardınız, fail2ban’ın engellediği IP listesine sahipsiniz. Bunları karşılaştırıp engellenen IP’lerin istek sayısını görmek istiyorsunuz:

# Nginx logdan IP bazlı istek sayısı (önceden işlenmiş)
# nginx_requests.txt formatı: IP istek_sayisi
cat nginx_requests.txt
# 192.168.1.100 4521
# 10.0.0.55 234
# 203.0.113.42 15632
# 198.51.100.7 892

# fail2ban engel listesi
# banned_ips.txt formatı: IP ban_tarihi
cat banned_ips.txt
# 203.0.113.42 2024-01-15
# 198.51.100.7 2024-01-14

# Engellenen IP'lerin istek sayısını bul
join <(sort nginx_requests.txt) <(sort banned_ips.txt)
# 198.51.100.7 892 2024-01-14
# 203.0.113.42 15632 2024-01-15

Şimdi engellenmemiş ama yüksek istek yapan IP’leri bulmak istiyorsunuz:

# Sadece nginx'te olup ban listesinde olmayanları göster
join -v 1 <(sort nginx_requests.txt) <(sort banned_ips.txt)

Senaryo 2: Kullanıcı Denetimi

Sistemde aktif kullanıcıları LDAP listesiyle karşılaştırıp tutarsızlıkları bulmak sysadmin’lerin sıkça yaptığı bir işlemdir:

# /etc/passwd'den aktif shell kullanıcılarını çıkar
grep -v "nologin|false" /etc/passwd | cut -d: -f1 | sort > /tmp/sistem_kullanicilari.txt

# LDAP'tan aktif kullanıcı listesi alındığını varsayalım
sort ldap_kullanicilari.txt > /tmp/ldap_sirali.txt

# Sistemde olup LDAP'ta olmayan kullanıcılar (orphan accounts)
join -v 1 /tmp/sistem_kullanicilari.txt /tmp/ldap_sirali.txt

# LDAP'ta olup sistemde olmayan kullanıcılar
join -v 2 /tmp/sistem_kullanicilari.txt /tmp/ldap_sirali.txt

Senaryo 3: Sistem Metrik Raporu Oluşturmak

Birden fazla monitoring scriptinin çıktısını birleştirerek kapsamlı bir rapor oluşturma:

#!/bin/bash
# sistem_rapor.sh

RAPOR_DIR="/tmp/rapor_$(date +%Y%m%d)"
mkdir -p $RAPOR_DIR

# Her sunucu için ayrı scriptler çalıştırıldığını ve
# sonuçların dosyalara yazıldığını varsayalım

# Sunucu adı ve CPU yükü
cat > $RAPOR_DIR/cpu_yuku.txt << EOF
web01 45
web02 23
db01 78
db02 34
EOF

# Sunucu adı ve bellek kullanımı (%)
cat > $RAPOR_DIR/bellek.txt << EOF
db01 82
db02 45
web01 67
web02 31
EOF

# Sunucu adı ve disk kullanımı (%)
cat > $RAPOR_DIR/disk.txt << EOF
db02 55
web01 43
web02 78
db01 91
EOF

# Üçlü join için önce ikili join yap, sonra üçüncüyü ekle
join <(sort $RAPOR_DIR/cpu_yuku.txt) <(sort $RAPOR_DIR/bellek.txt) | 
  sort -k1 > $RAPOR_DIR/cpu_bellek.txt

join $RAPOR_DIR/cpu_bellek.txt <(sort $RAPOR_DIR/disk.txt)

echo "Sunucu CPU_Yuku Bellek Disk"
join $RAPOR_DIR/cpu_bellek.txt <(sort $RAPOR_DIR/disk.txt)

Senaryo 4: CSV Dosyalarını Birleştirmek

Gerçek hayatta dosyalar genellikle CSV formatında gelir. join ile CSV işlemek için -t parametresini kullanırız:

# sunucu_bilgileri.csv
# hostname,ip,ortam
web01,192.168.1.10,prod
web02,192.168.1.11,prod
db01,192.168.1.20,staging

# sunucu_rolleri.csv
# hostname,rol,sahip
db01,database,veritabani-ekibi
web01,webserver,uygulama-ekibi
web02,webserver,uygulama-ekibi

# CSV join - virgülle ayrılmış, ilk alan üzerinden
join -t "," 
  <(sort -t "," -k1 sunucu_bilgileri.csv) 
  <(sort -t "," -k1 sunucu_rolleri.csv)

Çıktı:

db01,192.168.1.20,staging,database,veritabani-ekibi
web01,192.168.1.10,prod,webserver,uygulama-ekibi
web02,192.168.1.11,prod,webserver,uygulama-ekibi

İleri Seviye: paste ve join Birlikte Kullanmak

Bu iki komutu birleştirdiğinizde çok daha güçlü çözümler üretebilirsiniz. Örneğin birden fazla zaman serisini yan yana koyup analiz etmek:

# Saatlik bazda CPU metrik dosyaları var
# her dosya format: saat deger

# Beş sunucunun CPU verilerini tek raporda birleştir
# Önce join ile web01 ve web02'yi birleştir
join <(sort cpu_web01.txt) <(sort cpu_web02.txt) > /tmp/web_cpular.txt

# Sonra db sunucularını
join <(sort cpu_db01.txt) <(sort cpu_db02.txt) > /tmp/db_cpular.txt

# Son olarak paste ile ikisini yan yana getir
# (saat alanlarından birini kesmemiz gerekir)
paste /tmp/web_cpular.txt /tmp/db_cpular.txt | 
  awk '{print $1, $2, $3, $5, $6}' | 
  column -t

Yaygın Hatalar ve Çözümleri

join çıktısı boş veya eksik geliyor: Neredeyse her zaman sıralama problemidir. Dosyaları sort ile sıraladığınızdan emin olun. Özellikle sayısal sıralama için sort -n kullanmayı unutmayın.

Büyük/küçük harf uyumsuzluğu: join -i parametresiyle harf duyarsız karşılaştırma yapabilirsiniz. Ya da önceden tr '[:upper:]' '[:lower:]' ile normalize edin.

Boşluk ve tab karışıklığı: join varsayılan olarak whitespace’e göre böler ama birden fazla boşluğu tek alan olarak değerlendirmez. Bu durumda awk ile önceden alanları düzenlemek gerekebilir.

paste ile farklı uzunluktaki dosyalar: paste farklı satır sayısına sahip dosyaları birleştirince kısa olan dosya için boş alan bırakır. Bu davranışı bilmek önemlidir çünkü beklenmedik çıktılara yol açabilir.

# Dosya uzunluklarını kontrol et
wc -l dosya1.txt dosya2.txt

# join için sıralama kontrolü
sort -c dosya1.txt && echo "Sıralı" || echo "Sırasız"

Performans Notları

join ve paste komutları büyük dosyalarla çalışırken oldukça verimlidir çünkü satır satır işler, tüm dosyayı belleğe almaz. Ancak join için sıralama adımı eklenince sort komutu büyük dosyalarda bellek ve disk kullanabilir.

Birkaç milyon satırlık dosyalarla çalışıyorsanız:

# sort'un geçici dizinini ve bellek sınırını ayarla
sort --buffer-size=1G --temporary-directory=/data/tmp -k1 buyuk_dosya.txt > /tmp/sirali.txt

SQLite veya awk’la yapılan bazı işlemler çok büyük dosyalarda join‘den daha hızlı olabilir. 500 MB üzeri dosyalarda benchmark yapmanızı öneririm.

Sonuç

paste ve join komutları, Linux metin işleme araç kutusunun hafife alınan ama son derece değerli üyeleridir. paste, satırları yan yana getirmek ve basit yatay birleştirme işlemleri için ideal bir seçimken, join ilişkisel veri analizi gereken durumlarda SQL gerektirmeden güçlü JOIN işlemleri yapmanızı sağlar.

Günlük sysadmin görevlerinde log korelasyonu, kullanıcı denetimi, envanter raporlama ve sistem metrik analizi gibi işlemler için bu komutları kullanmaya başladığınızda hem scriptlerinizin okunabilirliği artar hem de gereksiz Python veya Perl scriptleri yazmaktan kurtulursunuz. Tek satırlık bir join komutu bazen onlarca satır kod yazmaktan sizi kurtarır.

Her iki komutun da temel kullanımını öğrendikten sonra process substitution, pipe zincirleri ve diğer metin işleme araçlarıyla kombinasyonlarını denemekten çekinmeyin. Komut satırının asıl gücü bu araçların birbirini tamamlamasında yatıyor.

Yorum yapın