Sistem yöneticiliğinde zamanın büyük bir kısmı tekrarlı işlemlerle geçer. Yüzlerce sunucuya aynı komutu göndermek, binlerce dosyayı tek tek işlemek ya da belirli koşullar sağlanana kadar bir servisi izlemek… Tüm bunları elle yapmak hem zaman kaybı hem de hata riski demek. İşte burada Bash döngüleri devreye giriyor. for, while ve until döngülerini gerçekten kavradığınızda, saatler süren manuel işleri birkaç satır kodla halledebiliyorsunuz.
for Döngüsü: Bilinen Listeler Üzerinde Gezinmek
for döngüsü, elinizde bir liste ya da aralık olduğunda kullanılır. Kaç iterasyon yapacağınızı önceden biliyorsunuz demektir.
Temel Sözdizimi
for degisken in liste; do
komutlar
done
En basit örnekle başlayalım. Birkaç sunucuya ping atmak istiyorsunuz:
#!/bin/bash
sunucular="web01 web02 web03 db01 db02"
for sunucu in $sunucular; do
echo "=== $sunucu kontrol ediliyor ==="
ping -c 2 -W 1 "$sunucu" > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "$sunucu: ERIŞILEBILIR"
else
echo "$sunucu: ERIŞILEMIYOR - Dikkat!"
fi
done
Bu script birkaç saniyede tüm sunucuları kontrol ediyor. Gerçek hayatta sunucu listesini bir dosyadan okumak daha pratik:
#!/bin/bash
# /etc/monitored_hosts dosyasından sunucu listesini oku
HOSTS_FILE="/etc/monitored_hosts"
LOG_FILE="/var/log/host_check_$(date +%Y%m%d).log"
if [ ! -f "$HOSTS_FILE" ]; then
echo "Hata: $HOSTS_FILE bulunamadi!" >&2
exit 1
fi
echo "Host kontrol basliyor: $(date)" | tee -a "$LOG_FILE"
for sunucu in $(cat "$HOSTS_FILE"); do
# Yorum satırlarını ve boş satırları atla
[[ "$sunucu" =~ ^#.*$ ]] && continue
[[ -z "$sunucu" ]] && continue
if ping -c 2 -W 2 "$sunucu" > /dev/null 2>&1; then
echo "[OK] $sunucu - $(date +%H:%M:%S)" | tee -a "$LOG_FILE"
else
echo "[HATA] $sunucu - $(date +%H:%M:%S)" | tee -a "$LOG_FILE"
# Kritik sunucu down ise mail gönder
echo "$sunucu erisilemez durumda!" | mail -s "ALERT: $sunucu DOWN" [email protected]
fi
done
C Stili for Döngüsü
Sayısal aralıklarla çalışırken C stili sözdizimi çok işe yarıyor:
for (( i=1; i<=10; i++ )); do
echo "Iterasyon: $i"
done
Bunu gerçek bir senaryoya dönüştürelim. Diyelim ki log rotasyon scriptiniz var ve son 30 günün loglarını arşivlemek istiyorsunuz:
#!/bin/bash
LOG_DIR="/var/log/uygulama"
ARSIV_DIR="/backup/logs"
GUN_SAYISI=30
mkdir -p "$ARSIV_DIR"
for (( gun=1; gun<=$GUN_SAYISI; gun++ )); do
tarih=$(date -d "$gun days ago" +%Y-%m-%d)
log_dosyasi="$LOG_DIR/app-${tarih}.log"
if [ -f "$log_dosyasi" ]; then
gzip -c "$log_dosyasi" > "$ARSIV_DIR/app-${tarih}.log.gz"
echo "Arşivlendi: $log_dosyasi"
rm "$log_dosyasi"
fi
done
echo "Log arşivleme tamamlandi."
Glob ve Dosya İşlemleri
for döngüsünün en sık kullandığım şekli dosya işlemleri. Bir dizindeki tüm .conf dosyalarına yedek almak mesela:
#!/bin/bash
KAYNAK="/etc/nginx/conf.d"
YEDEK="/backup/nginx/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$YEDEK"
for conf_dosyasi in "$KAYNAK"/*.conf; do
# Dosya var mı kontrol et (glob eşleşmezse)
[ -f "$conf_dosyasi" ] || continue
dosya_adi=$(basename "$conf_dosyasi")
cp "$conf_dosyasi" "$YEDEK/$dosya_adi"
echo "Yedeklendi: $dosya_adi"
done
echo "Toplam yedeklenen: $(ls $YEDEK | wc -l) dosya"
while Döngüsü: Koşul Sağlandığı Sürece Çalış
while döngüsü, iterasyon sayısını önceden bilmediğinizde kullanılır. Bir koşul doğru olduğu sürece döngü devam eder.
Temel Kullanım
while [ koşul ]; do
komutlar
done
Dosyadan Satır Satır Okuma
while read kombinasyonu, benim en çok kullandığım pattern’lardan biri. CSV dosyalarını işlemek, kullanıcı listelerini okumak, yapılandırma dosyalarını parse etmek için biçilmiş kaftan:
#!/bin/bash
# kullanici_listesi.csv formatı: kullanici_adi,email,grup
KULLANICI_DOSYASI="/tmp/yeni_kullanicilar.csv"
while IFS=',' read -r kullanici email grup; do
# Başlık satırını atla
[[ "$kullanici" == "kullanici_adi" ]] && continue
# Boş satırları atla
[[ -z "$kullanici" ]] && continue
echo "Kullanici olusturuluyor: $kullanici"
# Kullanıcı zaten varsa atla
if id "$kullanici" &>/dev/null; then
echo " [UYARI] $kullanici zaten mevcut, atlaniyor..."
continue
fi
# Kullanıcıyı oluştur
useradd -m -G "$grup" -c "$email" "$kullanici"
if [ $? -eq 0 ]; then
# Geçici şifre oluştur ve mail gönder
gecici_sifre=$(openssl rand -base64 12)
echo "$kullanici:$gecici_sifre" | chpasswd
echo "Geçici şifreniz: $gecici_sifre" | mail -s "Hesap Oluşturuldu" "$email"
echo " [OK] $kullanici olusturuldu"
else
echo " [HATA] $kullanici olusturulamadi!"
fi
done < "$KULLANICI_DOSYASI"
Servis İzleme ve Yeniden Başlatma
while döngüsünün klasik kullanım alanı sürekli çalışan izleme scriptleri. Bir servisin ayakta olup olmadığını kontrol eden basit ama etkili bir script:
#!/bin/bash
SERVIS="nginx"
KONTROL_ARALIGI=30 # saniye
MAX_YENIDEN_BASLATMA=3
yeniden_baslatma_sayaci=0
echo "$(date): $SERVIS izleme basliyor..."
while true; do
if ! systemctl is-active --quiet "$SERVIS"; then
echo "$(date): $SERVIS DOWN - Yeniden baslatilamaya calisiliyor..."
if [ $yeniden_baslatma_sayaci -lt $MAX_YENIDEN_BASLATMA ]; then
systemctl restart "$SERVIS"
sleep 5
if systemctl is-active --quiet "$SERVIS"; then
echo "$(date): $SERVIS basariyla yeniden baslandi"
yeniden_baslatma_sayaci=$((yeniden_baslatma_sayaci + 1))
else
echo "$(date): $SERVIS yeniden baslatma BASARISIZ!"
echo "$SERVIS yeniden baslatma basarisiz - Manuel mudahale gerekiyor!" |
mail -s "KRITIK: $SERVIS CALISMIYOIR" [email protected]
fi
else
echo "$(date): Maksimum yeniden baslatma sayisina ulasildi!"
echo "MAX yeniden baslatma limiti asildi - Insan mudahalesi gerekiyor!" |
mail -s "KRITIK: $SERVIS - Manuel Mudahale Gerekli" [email protected]
exit 1
fi
else
# Servis çalışıyor, sayacı sıfırla
yeniden_baslatma_sayaci=0
fi
sleep "$KONTROL_ARALIGI"
done
Disk Doluluk Uyarısı
Belirli bir eşiğe ulaşılana kadar bekleyen bir script:
#!/bin/bash
DISK_ESIGI=85 # yüzde
DIZIN="/"
UYARI_GONDERILDI=false
while true; do
KULLANIM=$(df "$DIZIN" | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$KULLANIM" -gt "$DISK_ESIGI" ]; then
if [ "$UYARI_GONDERILDI" = false ]; then
echo "$(date): UYARI - Disk kullanimi %$KULLANIM"
df -h "$DIZIN" | mail -s "Disk Doluluk Uyarisi: %$KULLANIM" [email protected]
UYARI_GONDERILDI=true
fi
else
UYARI_GONDERILDI=false
fi
sleep 300 # 5 dakikada bir kontrol
done
until Döngüsü: Koşul Yanlış Olduğu Sürece Çalış
until, while‘ın tam tersi mantıkla çalışır. Koşul yanlış olduğu sürece döngü devam eder, koşul doğru olduğunda durur. Yani “şu gerçekleşene kadar bekle” mantığı.
Temel Sözdizimi
until [ koşul ]; do
komutlar
done
Servis Başlayana Kadar Bekle
Bu pattern’i deployment scriptlerinde çok kullanıyorum. Bir uygulamayı başlattıktan sonra hazır olana kadar beklemek:
#!/bin/bash
SERVIS="postgresql"
MAX_BEKLEME=60 # saniye
gecen_sure=0
echo "PostgreSQL başlamasi bekleniyor..."
systemctl start "$SERVIS"
until systemctl is-active --quiet "$SERVIS"; do
if [ $gecen_sure -ge $MAX_BEKLEME ]; then
echo "Hata: $SERVIS $MAX_BEKLEME saniye içinde baslamadi!"
exit 1
fi
echo "Bekleniyor... ($gecen_sure saniye)"
sleep 2
gecen_sure=$((gecen_sure + 2))
done
echo "PostgreSQL hazir! ($gecen_sure saniyede basladi)"
Veritabanı Bağlantısını Bekle
CI/CD pipeline’larında container’ların birbirini beklemesi gerektiğinde bu çok işe yarıyor:
#!/bin/bash
DB_HOST="${DB_HOST:-localhost}"
DB_PORT="${DB_PORT:-5432}"
DB_USER="${DB_USER:-postgres}"
MAX_DENEME=30
deneme=0
echo "Veritabani baglantisi bekleniyor: $DB_HOST:$DB_PORT"
until pg_isready -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" > /dev/null 2>&1; do
deneme=$((deneme + 1))
if [ $deneme -ge $MAX_DENEME ]; then
echo "Hata: Veritabanina $MAX_DENEME denemede baglanamadi!"
exit 1
fi
echo "Baglanti denemesi $deneme/$MAX_DENEME - 3 saniye bekleniyor..."
sleep 3
done
echo "Veritabani baglantisi basarili!"
# Şimdi uygulamayı başlat
exec "$@"
Döngü Kontrolü: break ve continue
Döngüleri daha esnek kullanmak için break ve continue komutlarını bilmek şart.
break: Döngüyü tamamen sonlandırır. continue: Mevcut iterasyonu atlar, bir sonrakine geçer.
#!/bin/bash
# Büyük log dosyalarını bul, ilk 5 tanesini sıkıştır
SAYAC=0
LIMIT=5
for dosya in /var/log/**/*.log; do
[ -f "$dosya" ] || continue
boyut=$(du -m "$dosya" | cut -f1)
# 100MB'dan küçükse atla
if [ "$boyut" -lt 100 ]; then
continue
fi
echo "Sikistiriliyor: $dosya ($boyut MB)"
gzip "$dosya"
SAYAC=$((SAYAC + 1))
# 5 dosyadan sonra dur
if [ $SAYAC -ge $LIMIT ]; then
echo "Limit doldu ($LIMIT dosya islendi)"
break
fi
done
echo "Toplam islenen: $SAYAC dosya"
İç İçe Döngüler
Bazen birden fazla boyutta iterasyon gerekir. Sunucu x uygulama matrisi gibi:
#!/bin/bash
ORTAMLAR="dev staging prod"
SERVISLER="nginx postgresql redis"
for ortam in $ORTAMLAR; do
echo ""
echo "=== $ortam ortami kontrol ediliyor ==="
for servis in $SERVISLER; do
# Her ortamdaki her servisi kontrol et
# Gerçekte bu bir SSH komutu olabilir
durum=$(ssh "ops@${ortam}-server" "systemctl is-active $servis" 2>/dev/null)
if [ "$durum" = "active" ]; then
echo " [OK] $servis"
else
echo " [HATA] $servis - Durum: $durum"
fi
done
done
Paralel İşlem ile Döngüleri Hızlandırma
Büyük listeleri sıralı işlemek zaman alabilir. Background job’lar ile paralel çalışmak:
#!/bin/bash
SUNUCULAR=(web01 web02 web03 web04 web05 web06 web07 web08)
MAX_PARALEL=4
AKTIF_IS=0
for sunucu in "${SUNUCULAR[@]}"; do
# Maksimum paralel iş sayısını aşmayı bekle
while [ $AKTIF_IS -ge $MAX_PARALEL ]; do
wait -n 2>/dev/null || wait
AKTIF_IS=$((AKTIF_IS - 1))
done
# İşi arka planda başlat
{
echo "[$sunucu] Yedek aliniyor..."
rsync -az /etc/ "backup@backup-server:/backup/$sunucu/etc/" 2>&1
echo "[$sunucu] Yedek tamamlandi"
} &
AKTIF_IS=$((AKTIF_IS + 1))
done
# Kalan tüm işlerin bitmesini bekle
wait
echo "Tüm yedekler tamamlandi!"
Gerçek Dünya: Deployment Script
Tüm öğrendiklerimizi bir araya getiren gerçekçi bir deployment scripti:
#!/bin/bash
set -euo pipefail
UYGULAMALAR=("api-service" "worker-service" "scheduler-service")
ORTAM="${1:-staging}"
IMAGE_TAG="${2:-latest}"
BASARI_SAYISI=0
HATA_SAYISI=0
deploy_uygulama() {
local uygulama="$1"
local tag="$2"
echo "[$uygulama] Deploy basliyor: $tag"
# Image'ı çek
if ! docker pull "sirket/$uygulama:$tag" > /dev/null 2>&1; then
echo "[$uygulama] HATA: Image cekilemedi!"
return 1
fi
# Container'ı yeniden başlat
docker-compose -f "docker-compose.$ORTAM.yml" up -d "$uygulama"
# Sağlık kontrolü: 60 saniye boyunca bekle
local bekleme=0
until docker-compose -f "docker-compose.$ORTAM.yml" ps "$uygulama" | grep -q "healthy"; do
if [ $bekleme -ge 60 ]; then
echo "[$uygulama] HATA: Saglik kontrolu zaman asimina ugradi!"
return 1
fi
sleep 5
bekleme=$((bekleme + 5))
done
echo "[$uygulama] Deploy basarili! ($bekleme saniyede hazir)"
return 0
}
echo "Deploy basliyor: $ORTAM ortami, tag: $IMAGE_TAG"
echo "Uygulamalar: ${UYGULAMALAR[*]}"
echo ""
for uygulama in "${UYGULAMALAR[@]}"; do
if deploy_uygulama "$uygulama" "$IMAGE_TAG"; then
BASARI_SAYISI=$((BASARI_SAYISI + 1))
else
HATA_SAYISI=$((HATA_SAYISI + 1))
echo "[$uygulama] Deploy basarisiz, devam ediliyor..."
fi
done
echo ""
echo "=== Deploy Ozeti ==="
echo "Basarili: $BASARI_SAYISI/${#UYGULAMALAR[@]}"
echo "Basarisiz: $HATA_SAYISI/${#UYGULAMALAR[@]}"
if [ $HATA_SAYISI -gt 0 ]; then
echo "Bazi uygulamalar deploy edilemedi!" | mail -s "Deploy Uyarisi: $ORTAM" [email protected]
exit 1
fi
echo "Tum uygulamalar basariyla deploy edildi!"
Döngülerde Sık Yapılan Hatalar
Boşluk içeren dosya adları: for dosya in $(ls) yerine her zaman glob kullanın.
# Yanlis - bosluk iceren dosya adlarinda bozulur
for dosya in $(ls /tmp); do ...
# Dogru
for dosya in /tmp/*; do ...
Sonsuz döngüden çıkamamak: while true kullanıyorsanız her zaman bir çıkış koşulu ve break ekleyin. Ya da scripti timeout komutuyla çalıştırın:
timeout 3600 ./izleme_scripti.sh
IFS sorunları: while read kullanırken IFS’i ayarlamayı unutmayın, yoksa satır başı ve sonu boşlukları beklenmedik sorunlara yol açar.
# Guvenli sekilde oku
while IFS= read -r satir; do
echo "$satir"
done < dosya.txt
Sonuç
for, while ve until döngüleri Bash scripting’in omurgasını oluşturur. Bunların hangisini ne zaman kullanacağınızı özetseyecek olursam:
- for: Eleman sayısını önceden bildiğinizde, dosya listeleri, array iterasyonları
- while: Koşul doğru olduğu sürece çalışması gereken durumlar, sürekli izleme, satır satır okuma
- until: “Şu gerçekleşene kadar bekle” senaryoları, servis başlamasını bekleme, deployment sonrası sağlık kontrolü
Bu üç döngüyü break, continue ve paralel işleme teknikleriyle birleştirdiğinizde, saatlerinizi alan manuel işleri dakikalar içinde otomatik hale getirebilirsiniz. Sysadmin’in en büyük silahı tembellik değil, akıllı tembellik. Bir işi iki kez yapıyorsanız, üçüncüde script yazma vakti gelmiş demektir.