
Linux'ta Bash Script Yazma: Temel Otomasyon Rehberi
Bash script ile Linux görevlerini nasıl otomatize edersiniz? Değişkenler, koşullar, döngüler ve fonksiyonlar ile temel bash scripting öğrenin.
Linux'ta Bash Script Yazma: Sunucu Yönetimi için Pratik Otomasyon Rehberi (2026)
Bash script, Linux sunucusunda tekrar eden işleri otomatize etmenin en doğal yoludur: yedekleme, log temizliği, disk kullanımı uyarısı, servis monitoring, deploy script'leri — hepsi 50-150 satırlık bash kodu ile çözülür. Python veya Go gerektirmez; başka kütüphane gerektirmez; her Linux dağıtımında çalışır. Bu rehberde Buyukweb VDS müşterilerimiz için bash'i sıfırdan değil, gerçek sunucu senaryolarına yönelik anlatıyoruz: variable, döngü, hata yönetimi, cron entegrasyonu, gerçek-dünya örnekleri.
Buyukweb perspektifi: VDS'de root yetkiniz var; bash script'leriniz
/usr/local/bin/veya~/bin/altına koyulup cron ile zamanlanır. Buyukweb ekibi sunuculara müdahale ederken çoğunlukla bash script'i tercih eder — Ansible/Puppet karmaşıklığına gerek yok küçük-orta sunucuda. Tercih etmeyin: internetten kopyalanan "30 saniyede sunucu kuran" mega script'leri körlemesinecurl | bashile çalıştırmayı; her satırı anlayarak kopyalayın. Senaryoda hata olursa kritik veri kaybedebilirsiniz. Önce dry-run, sonra apply alışkanlığı kurun.
İlk Bash Script — 5 Dakikada Çalışır Hale
# 1. Dosya oluştur
nano disk-rapor.sh
İçeriği:
#!/bin/bash
# Disk kullanım raporu — basit örnek
echo "=========================================="
echo " Sunucu Disk Raporu - $(date +'%F %H:%M')"
echo "=========================================="
echo ""
echo "Hostname: $(hostname)"
echo "Uptime: $(uptime -p)"
echo ""
echo "Disk kullanımı:"
df -h | grep -v tmpfs
echo ""
echo "En büyük 5 dizin (/home altı):"
du -sh /home/*/ 2>/dev/null | sort -rh | head -5
# 2. Çalıştırma izni ver
chmod +x disk-rapor.sh
# 3. Çalıştır
./disk-rapor.sh
Shebang Satırı
#!/bin/bash # Doğrudan /bin/bash
#!/usr/bin/env bash # PATH'tan bash bul (taşınabilir)
#!/bin/sh # POSIX shell, daha sınırlı ama her sistemde var
Tavsiye:
/usr/bin/env bashtaşınabilirlik için en güvenli; macOS, BSD, Linux her yerde çalışır./bin/shise dash veya ash olabilir; bash'a özgü özellikler (array,[[ ]]) çalışmaz.
Değişkenler
# Atama (eşittir etrafında BOŞLUK YOK)
ISIM="Buyukweb"
YIL=2026
DIZIN=/var/www
TARIH=$(date +%Y%m%d) # komut çıktısını değişkene al
# Kullanım
echo "Şirket: $ISIM"
echo "Yıl: ${YIL}" # küme parantezi ile sınırı belirt
echo "Bugün: $TARIH"
echo "Dizin: $DIZIN/site/"
# Read-only (sabit)
readonly MAX_RETRY=3
# Default değer (parameter expansion)
LOG_DIR="${LOG_DIR:-/var/log/myapp}" # eğer set edilmemişse default
# Komut satırı argümanları
echo "Script adı: $0"
echo "İlk argüman: $1"
echo "Tüm argümanlar: $@"
echo "Argüman sayısı: $#"
Önemli: Değişkenleri çift tırnak içinde kullanın (
"$VAR"şeklinde). Boşluklu dosya adlarında veya glob expansion'a karşı koruma sağlar. Tek tırnak değişken expand etmez ('$VAR'literal yazılır).
Koşullar
# if-else
if [ -f "/etc/hostname" ]; then
echo "Dosya mevcut"
elif [ -d "/etc" ]; then
echo "Dizin var ama dosya yok"
else
echo "Hiçbiri yok"
fi
# Daha modern: [[ ]] (bash-only, POSIX değil)
if [[ "$ISIM" == "Buyukweb" && $YIL -ge 2026 ]]; then
echo "Doğru"
fi
# case
case "$1" in
start) echo "Başlatılıyor"; ;;
stop) echo "Durduruluyor"; ;;
restart) echo "Yeniden başlatılıyor"; ;;
*) echo "Kullanım: $0 {start|stop|restart}"; exit 1 ;;
esac
Yaygın Test Operatörleri
| Test | Anlam |
|---|---|
-f FILE |
dosya mı? |
-d DIR |
dizin mi? |
-e PATH |
varlığı (dosya/dizin/link) |
-r FILE |
okunabilir mi? |
-w FILE |
yazılabilir mi? |
-x FILE |
çalıştırılabilir mi? |
-z STR |
string boş mu? |
-n STR |
string boş değil mi? |
STR1 == STR2 |
eşit |
NUM1 -eq NUM2 |
sayısal eşit |
NUM1 -gt NUM2 |
büyük |
NUM1 -lt NUM2 |
küçük |
Döngüler
# for - liste üzerinde
for SERVIS in nginx mariadb php-fpm; do
systemctl status "$SERVIS" --no-pager
done
# for - C-style
for ((i=1; i<=10; i++)); do
echo "İterasyon $i"
done
# for - dosyalar üzerinde
for LOG in /var/log/*.log; do
echo "Log: $LOG ($(stat -c %s "$LOG") byte)"
done
# while - koşul tabanlı
SAYAC=0
while [ $SAYAC -lt 5 ]; do
echo "Sayaç: $SAYAC"
((SAYAC++))
done
# while - dosyayı satır satır oku
while IFS= read -r SATIR; do
echo "Satır: $SATIR"
done < /etc/hostname
# until - while'ın tersi (false olduğu sürece)
until ping -c 1 8.8.8.8 &>/dev/null; do
echo "Network bekliyor..."
sleep 2
done
Fonksiyonlar
# Tanımlama
log_mesaj() {
local LEVEL=$1
local MESAJ=$2
local TARIH=$(date +'%F %T')
echo "[$TARIH] [$LEVEL] $MESAJ" | tee -a /var/log/script.log
}
# Çağırma
log_mesaj "INFO" "Script başlatıldı"
log_mesaj "ERROR" "Veritabanı bağlantısı başarısız"
# Değer döndüren fonksiyon
disk_yuzdesi() {
local YOL=${1:-/}
df "$YOL" | tail -1 | awk '{print $5}' | tr -d '%'
}
YUZDE=$(disk_yuzdesi /home)
echo "Disk yüzdesi: %$YUZDE"
# Exit code ile başarı/başarısızlık
servis_calisir_mi() {
systemctl is-active "$1" &>/dev/null
}
if servis_calisir_mi "nginx"; then
echo "Nginx çalışıyor"
else
echo "Nginx kapalı"
fi
Local değişken kullanın: Fonksiyon içinde
local VAR=...ile tanımlamazsanız global olur ve dış değişkenleri kirletir.
Hata Yönetimi (set Bayrakları)
Production script'inin başına şu satırları mutlaka ekleyin:
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
Açıklama:
set -e— herhangi bir komut hata verirse script dur (exit code != 0)set -u— tanımsız değişken kullanılırsa hataset -o pipefail— pipe içindeki herhangi komut başarısızsa pipeline başarısız sayılsınIFS=$'\n\t'— alan ayırıcıyı yeni-satır ve tab yap (boşluklu dosya adı sorununu önler)
# Manuel hata kontrolü
mkdir -p /backup || { echo "ERROR: Backup dizini oluşturulamadı"; exit 1; }
# Cleanup için trap
TEMP_DIR=$(mktemp -d)
cleanup() {
echo "Temizlik yapılıyor..."
rm -rf "$TEMP_DIR"
}
trap cleanup EXIT INT TERM
Pratik Script: Otomatik Veritabanı + Dosya Yedekleme
#!/bin/bash
# /usr/local/bin/site-yedek.sh
set -euo pipefail
# Konfigürasyon
DB_USER="backup_user"
DB_PASS="GUVENLI_SIFRE"
DB_NAME="wp_buyukweb"
SITE_DIR="/var/www/buyukweb.com"
YEDEK_DIR="/backup/site"
TARIH=$(date +'%Y%m%d_%H%M%S')
GUNLER=14 # eski yedek saklama gün sayısı
# Logging
LOG="/var/log/site-yedek.log"
log() { echo "[$(date +'%F %T')] $*" | tee -a "$LOG"; }
# Yedek dizini
mkdir -p "$YEDEK_DIR"
log "Yedekleme başladı"
# Veritabanı yedeği
log "MySQL dump alınıyor..."
mysqldump --single-transaction --quick \
-u "$DB_USER" -p"$DB_PASS" "$DB_NAME" \
| gzip > "$YEDEK_DIR/db-$TARIH.sql.gz"
log "DB yedek tamam: $(du -h "$YEDEK_DIR/db-$TARIH.sql.gz" | cut -f1)"
# Dosya yedeği
log "Dosya tar.gz alınıyor..."
tar -czf "$YEDEK_DIR/files-$TARIH.tar.gz" \
-C "$(dirname "$SITE_DIR")" "$(basename "$SITE_DIR")"
log "Dosya yedek tamam: $(du -h "$YEDEK_DIR/files-$TARIH.tar.gz" | cut -f1)"
# Eski yedekleri temizle
log "$GUNLER günden eski yedekler siliniyor..."
find "$YEDEK_DIR" -name '*.gz' -mtime +"$GUNLER" -delete
# Toplam disk kullanımı
log "Toplam yedek boyutu: $(du -sh "$YEDEK_DIR" | cut -f1)"
log "Yedekleme tamam"
Cron'a ekle:
# crontab -e
0 3 * * * /usr/local/bin/site-yedek.sh
Pratik Script: Disk Kotası Uyarı (mail bildirim)
#!/bin/bash
set -euo pipefail
ESIK=85 # %85 üzerinde uyarı
EMAIL="[email protected]"
DURUM=""
while read -r KULLANIM YOL; do
YUZDE=${KULLANIM%\%}
if [ "$YUZDE" -ge "$ESIK" ]; then
DURUM+="UYARI: $YOL %$YUZDE dolu\n"
fi
done < <(df -h --output=pcent,target | tail -n +2 | awk '$1 ~ /[0-9]+%/')
if [ -n "$DURUM" ]; then
echo -e "$DURUM" | mail -s "Disk Uyarısı: $(hostname)" "$EMAIL"
fi
Pratik Script: Servis Sağlık Kontrolü ve Otomatik Yeniden Başlat
#!/bin/bash
set -euo pipefail
SERVISLER=("nginx" "mariadb" "php-fpm")
LOG="/var/log/servis-saglik.log"
log() { echo "[$(date +'%F %T')] $*" >> "$LOG"; }
for SERVIS in "${SERVISLER[@]}"; do
if ! systemctl is-active --quiet "$SERVIS"; then
log "$SERVIS DOWN — yeniden başlatılıyor"
if systemctl restart "$SERVIS"; then
log "$SERVIS başarıyla başlatıldı"
else
log "HATA: $SERVIS yeniden başlatılamadı, manuel müdahale gerekiyor"
echo "$SERVIS yeniden başlatılamadı: $(hostname)" \
| mail -s "ACIL: Servis Hatası" [email protected]
fi
fi
done
Cron 5 dakikada bir:
*/5 * * * * /usr/local/bin/servis-saglik.sh
Pratik Script: Log Rotasyonu
logrotate kullanmadan basit:
#!/bin/bash
set -euo pipefail
LOG_DIR="/var/log/myapp"
ESKI_GUN=30
SIKISTIR_GUN=7
# 7 günden eski log'ları sıkıştır
find "$LOG_DIR" -name "*.log" -type f -mtime +"$SIKISTIR_GUN" \
! -name "*.gz" -exec gzip {} \;
# 30 günden eski sıkıştırılmış log'ları sil
find "$LOG_DIR" -name "*.log.gz" -type f -mtime +"$ESKI_GUN" -delete
Pratik Script: Apache Access Log Analizi
#!/bin/bash
LOG_DOSYA="/var/log/nginx/access.log"
echo "=== En çok ziyaret edilen 10 URL ==="
awk '{print $7}' "$LOG_DOSYA" | sort | uniq -c | sort -rn | head -10
echo ""
echo "=== En çok istek atan 10 IP ==="
awk '{print $1}' "$LOG_DOSYA" | sort | uniq -c | sort -rn | head -10
echo ""
echo "=== HTTP durum kodu dağılımı ==="
awk '{print $9}' "$LOG_DOSYA" | sort | uniq -c | sort -rn
echo ""
echo "=== 404 alan URL'ler ==="
awk '$9 == 404 {print $7}' "$LOG_DOSYA" | sort | uniq -c | sort -rn | head -10
Best Practices (Kalıcı Alışkanlıklar)
1. shebang her zaman: #!/bin/bash veya #!/usr/bin/env bash
2. set -euo pipefail her production script'inde
3. Değişkenleri "$" ve çift tırnak içinde kullan: "${VAR}"
4. Komut substitution: $(...) — eski `...` yerine kullan
5. Check exit code:
if komut; then ... fi
veya: komut || hata_isle
6. Hardcoded path yerine değişken:
ISIM="/var/www/site"
tar -C "$ISIM" .
7. Hassas veri ENV'den oku, script'te değil:
DB_PASS="${DB_PASSWORD:?DB_PASSWORD env tanımlı olmalı}"
8. Logging: tüm önemli adımları log'a yaz
log() { echo "[$(date +'%F %T')] $*" | tee -a "$LOG_FILE"; }
9. Cleanup için trap kullan:
trap 'rm -f "$TMPFILE"' EXIT
10. shellcheck ile linting yap:
sudo apt install shellcheck
shellcheck script.sh
11. Script'lerin yedeği: git ile takip et, /usr/local/bin'e symlink
12. Deneme yapmadan production'da çalıştırma:
bash -n script.sh # syntax check
bash -x script.sh # debug, her satırı yazdır
DRY_RUN=1 ./script.sh # kendi flag'inle dry-run modu
Cron ile Zamanlama
# Cron formatı: dakika saat gün-ay ay haftanin-günü komut
# * * * * *
# 0-59 0-23 1-31 1-12 0-7
# Her dakika
* * * * * /usr/local/bin/health.sh
# Her 5 dakikada
*/5 * * * * /usr/local/bin/check.sh
# Her gün gece 3'te
0 3 * * * /usr/local/bin/backup.sh
# Pazartesi sabah 6'da
0 6 * * 1 /usr/local/bin/weekly-report.sh
# Ayın 1'inde gece yarısı
0 0 1 * * /usr/local/bin/monthly-cleanup.sh
# Crontab düzenle
crontab -e
# Mevcut cron'ları gör
crontab -l
# Cron log'u (ayarlanmışsa)
tail -f /var/log/cron # AlmaLinux/Rocky
tail -f /var/log/syslog | grep CRON # Ubuntu
Cron tuzakları: PATH cron ortamında minimumdur (
/usr/bin:/bin). Script'iniz/usr/local/binveya/opt/...altındaysa tam yol yazın. Veya script başınaPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binekleyin.
Sık Sorulan Sorular
Buyukweb VDS'de bash script'lerimi nereye koyayım?
Sunucuda root olduğunuz için /usr/local/bin/ altına koyun (tüm kullanıcılar PATH'tan erişir). Sadece kişisel script'ler ~/bin/'de tutulabilir. Her zaman chmod +x script.sh ile çalıştırılabilir yapın.
Neden #!/bin/sh yerine #!/bin/bash kullanmalıyım?
/bin/sh farklı dağıtımlarda farklı shell olabilir (Debian'da dash, BusyBox'ta ash). Bash'a özgü array'ler, [[ ]], <(), parameter expansion özellikleri çalışmayabilir. Production ortamında bash kullanın veya gerçekten POSIX-uyumlu yazıp shellcheck -s sh script.sh ile doğrulayın.
shellcheck nedir, neden kullanmalıyım?
shellcheck bir bash linter — script'inizdeki yaygın hataları (tırnak unutmak, gereksiz cat kullanımı, race condition'lar) tespit eder. Buyukweb sunucularında apt install shellcheck veya dnf install ShellCheck ile kurabilirsiniz; CI'de de çalıştırılabilir.
Bash mı Python mı, hangisini ne zaman seçmeliyim?
- Bash: sistem komutu zinciri (mysqldump, tar, find, sed), <500 satır, hızlı tek-amaçlı görev
- Python: karmaşık veri işleme (JSON parsing, API çağrıları), yapısal kod, test gereksinimi
Dosya yedekleme için bash; Stripe API ile fatura kontrolü için Python.
Cron'da script çalışmıyor, debug nasıl?
# Script'in çıktısını log'a al
0 3 * * * /usr/local/bin/script.sh >> /var/log/script.log 2>&1
# Cron PATH eksik olabilir, scriptin ilk satırına ekle:
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Cron çalıştığını test et
* * * * * /bin/echo "Cron çalıştı $(date)" >> /tmp/cron-test.log
Script'imde hassas veri (şifre) var, nasıl güvenli saklayayım?
Asla script içinde hardcode etmeyin. 3 yöntem:
- ENV variable:
source /root/.envile yükle - Konfig dosyası:
chmod 600 /etc/script.conf(sadece root okur) - systemd EnvironmentFile: systemd unit ile kombinasyon
# /etc/script.conf
DB_PASS="GuvenliSifre123!"
# Script'te
source /etc/script.conf
mysqldump -u user -p"$DB_PASS" db > yedek.sql
Bash'in alternatifi var mı (zsh, fish)?
Production sunucularda bash standart. zsh, fish daha kullanıcı dostu ama:
- Sistem script'leri (cron, init) bash bekler
- Standart Linux paketleri bash'ta gelir
- shellcheck ve diğer araçlar bash optimize
Kullanıcı shell'iniz olarak zsh seçebilirsiniz, ama script'leri bash'ta yazın.
set -e her zaman doğru mu?
Çoğu zaman evet. Ama bazı durumlarda istenmeyen davranışa yol açabilir:
set -e
GREP_SONUC=$(grep "x" dosya || true) # || true ekle ki grep boş bulunca dur etmesin
İncelikli senaryolarda || true, || { ... } veya if komut; then ... fi kullanın.
Script'imi systemd service yapmak için?
Cron yerine systemd timer + service kombinasyonu daha esnek:
# /etc/systemd/system/site-yedek.service
[Unit]
Description=Site Backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/site-yedek.sh
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/site-yedek.timer
[Unit]
Description=Daily site backup
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl enable --now site-yedek.timer
sudo systemctl list-timers
journalctl -u site-yedek.service
Sonuç
Bash script Linux sunucu yönetiminin en pratik aracı. Yedekleme, monitoring, deploy, log analiz — hepsini 50-150 satırda halledersiniz. Buyukweb VDS müşterilerimize tavsiyemiz: set -euo pipefail ile başlayın, shellcheck ile lint yapın, cron veya systemd timer ile zamanlayın, hassas veriyi ENV'de tutun, her önemli adımı log'a yazın. 5-10 günlük yatırımla yıllık 100+ saat kazanırsınız.
Soru ve teknik destek için: 0850 302 60 70.
İlgili Büyükweb Hizmetleri
Bash otomasyon için altyapı paketleri:
- VDS Sunucu — root SSH, dilediğiniz cron stack
- E5 v4 VDS — Xeon E5 v4 + NVMe + RAM
- Türkiye VDS — Bursa Tier 3 datacenter
- Linux VDS — AlmaLinux/Rocky/Ubuntu/Debian
- Linux Hosting — paylaşımlı, sınırlı SSH/cron
Sorularınız için 0850 302 60 70 numaralı destek hattımıza veya iletişim sayfamıza yazabilirsiniz.
Linux & Komut Satırı İlgili Hizmetlerimiz
Bu yazıda anlatılan teknik konuyu profesyonel altyapıyla deneyimleyin
Etiketler:

