VPS.TC
| $
Sunucu Durumu
Turkey İstanbul, Türkiye
Aktif
USA New York, ABD
Aktif
Sepet Toplamı:
Sepeti Görüntüle
Bash Script Nedir? Linux Otomasyonu Rehberi
Linux

Bash Script Nedir? Linux Otomasyonu Rehberi

Defne avatarı Defne Eylül 5, 2026 11 dk okuma 0 Yorumlar
Paylaş:

Bash Script Nedir ve Linux Otomasyonu Nasıl Kurulur?

Gece vardiyasında aynı komutu üçüncü kez yazarken sorun çoğu zaman komutta değildir. Sorun, o işi hâlâ elle yapıyor olmamızdır. Birkaç dosyayı kontrol etmek, disk kullanımını ölçmek, eski logları arşivlemek veya servisleri belirli bir sırayla yeniden başlatmak kısa vadede kolay görünür. Bir süre sonra vakit kaybettirir ve insan hatasına açık hâle gelir.

Bash script nedir? Bash tarafından çalıştırılan; komutları, değişkenleri ve kontrol yapılarını tek bir dosyada birleştiren otomasyon betiğidir. Linux sunucuda elle yaptığınız adımları sıraya koyabilir, koşullara bağlayabilir, çıktı üretebilir ve cron gibi zamanlayıcılarla çalıştırabilirsiniz.

🚀 VPS Sunucu ile Hızınızı Artırın!

Yüksek performanslı SSD depolama ve %99.9 uptime garantisi ile projelerinizi hızlandırın.

Hemen Başla

Ben Bash script’i küçük sistem yönetimi işleri için hâlâ pratik buluyorum. Her iş için YAML dosyası hazırlamak gerekmiyor. Fakat iki kez tekrarladığım bir işi üçüncü kez elle yapmadan önce kendime şunu soruyorum: “Bunu yarın başka biri çalıştırsa ne olur?” Cevap belirsizse script’i yazıp güvenli hâle getiriyorum.

Bir Bash script hangi parçalarla çalışır?

Bash script dosyaları çoğunlukla .sh uzantısıyla kaydedilir. Uzantı zorunlu değildir; Linux için dosyanın içeriği ve çalıştırma biçimi daha önemlidir. Yine de .sh, dosyanın bir shell betiği olduğunu hızlıca anlatır.

Dosyanın en üstünde kullanılacak yorumlayıcıyı belirtmek iyi bir alışkanlıktır:

☁️ Cloud Sunucu ile Esneklik Kazanın!

Ölçeklenebilir kaynaklar ve anlık yedekleme ile bulutun gücünü deneyimleyin.

Keşfet
#!/usr/bin/env bash

printf 'Merhaba, %sn' "$USER"

İlk satıra shebang denir. /usr/bin/env bash ifadesi Bash’i sistemin PATH değişkeninde arar. Bazı dağıtımlarda Bash yolu doğrudan /bin/bash olabilir. env kullanmak farklı sistemler arasında taşınabilirliği bir miktar artırır.

printf kullandım çünkü biçimlendirme davranışı echo‘ya göre daha öngörülebilirdir. Basit bir mesaj için ikisi de iş görür. Script büyüdükçe küçük belirsizliklerin birikmesini istemem.

İlk script’i oluşturma ve çalıştırma

Önce dosyayı açın:

vim disk-kontrol.sh

İçine şu satırları ekleyebilirsiniz:

#!/usr/bin/env bash

set -u

printf 'Hostname: %sn' "$(hostname)"
printf 'Tarih: %sn' "$(date '+%Y-%m-%d %H:%M:%S')"
printf 'Disk kullanımı:n'
df -h /

set -u, tanımlanmamış bir değişken kullanıldığında script’in hata vermesini sağlar. Tek başına bütün hataları yakalamaz; yine de yazım hatalarını erkenden görmeme yardımcı olur.

Dosyayı çalıştırılabilir yapmak için:

chmod +x disk-kontrol.sh
./disk-kontrol.sh

Alternatif olarak izin eklemeden doğrudan Bash’e verebilirsiniz:

bash disk-kontrol.sh

İki yöntem arasındaki fark önemlidir. ./disk-kontrol.sh dosyanın çalıştırma iznine ve doğru shebang satırına güvenir. bash disk-kontrol.sh ise dosyayı özellikle Bash ile çalıştırır. Bash’e özgü diziler veya [[ ... ]] kullanıyorsanız sh ile çalıştırmayın; sh script.sh bazı sistemlerde farklı bir shell çağırabilir.

Değişkenler ve komut çıktıları

Script’lerin kullanışlı hâle gelmesi, sabit metinleri değişkenlerden ayırınca başlar. Değişken atarken eşittir işaretinin çevresinde boşluk bırakılmaz:

#!/usr/bin/env bash

BACKUP_DIR="/var/backups"
HOST="$(hostname -s)"
NOW="$(date '+%Y%m%d-%H%M%S')"

printf 'Sunucu: %sn' "$HOST"
printf 'Yedek dizini: %sn' "$BACKUP_DIR"
printf 'Zaman etiketi: %sn' "$NOW"

Değişkenleri kullanırken çift tırnakları ihmal etmeyin. Özellikle dosya yollarında boşluk bulunabiliyorsa "$BACKUP_DIR" ile $BACKUP_DIR aynı davranmayabilir. Sunucularımda boşluk içeren yolları tercih etmiyorum ama script’i güvenli yazmak için bu alışkanlığı koruyorum.

Komut çıktısını değişkene almak için $(...) kullanılır. Eski backtick biçimi de çalışır; iç içe komutlarda okunması daha zordur.

Argüman almak

Bir script’in her seferinde dosyanın içindeki yolu değiştirmenizi istemesi pratik değildir. Komut satırı argümanları burada devreye girer:

#!/usr/bin/env bash

if [[ $# -ne 1 ]]; then
    printf 'Kullanım: %s DİZİNn' "$0" >&2
    exit 1
fi

TARGET="$1"

if [[ ! -d "$TARGET" ]]; then
    printf 'Hata: dizin bulunamadı: %sn' "$TARGET" >&2
    exit 2
fi

du -sh -- "$TARGET"

$# verilen argüman sayısını, $1 ilk argümanı, $0 ise script’in adını temsil eder. Buradaki --, yolun tireyle başlaması gibi durumlarda komutun bunu seçenek sanmasını engeller. Küçük bir ayrıntı. Dosya işlemlerinde küçük ayrıntılar genellikle gece vardiyasının büyük ayrıntılarına dönüşür.

Koşullar ve çıkış kodları

Otomasyonun güvenilir olması için komutları art arda çalıştırmak yetmez. Bir adım başarısız olduğunda sonraki adımın çalışıp çalışmayacağına karar vermek gerekir.

#!/usr/bin/env bash

SERVICE="nginx"

if systemctl is-active --quiet "$SERVICE"; then
    printf '%s çalışıyor.n' "$SERVICE"
else
    printf '%s çalışmıyor.n' "$SERVICE" >&2
    exit 1
fi

systemctl is-active --quiet ekrana gereksiz çıktı basmadan yalnızca çıkış kodu döndürür. Shell’de 0 başarı, sıfır dışındaki değerler hata kabul edilir. Yeni başlayanların ters bulduğu bir ayrıntıdır: Bash’te doğru kabul edilen durum 0‘dır.

Dosya kontrollerinde yaygın test operatörlerinden bazıları şöyledir:

Test Anlamı
-f Normal dosya var mı?
-d Dizin var mı?
-r Okunabilir mi?
-w Yazılabilir mi?
-s Dosya boş değil mi?

Birden fazla komutun başarısızlığında script’i durdurmak için şu başlangıç satırı sık kullanılır:

set -Eeuo pipefail

-e başarısız bir komutta çıkmayı, -u tanımsız değişkenleri hata saymayı, pipefail ise pipe içindeki herhangi bir komutun hatasını üst komuta taşımayı sağlar. -E, hata yakalama davranışının fonksiyonlar ve alt kabuklarda daha tutarlı olmasına yardım eder.

Bu seçenekleri körlemesine eklemek de doğru değildir. Bazı komutlar beklenen koşullarda sıfır dışı kod döndürebilir. Örneğin grep, eşleşme bulamadığında hata değil bilgi niteliğinde bir çıkış kodu döndürür. Script’in hangi adımda ne beklediğini bilerek kullanın.

Fonksiyonlar, döngüler ve tekrar eden işler

Script uzadıkça aynı kodu kopyalamak yerine fonksiyon kullanırım:

log() {
    printf '[%s] %sn' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
}

fail() {
    log "HATA: $*" >&2
    exit 1
}

log 'Kontrol başlıyor'
[[ -d /var/log ]] || fail '/var/log bulunamadı'
log 'Kontrol tamamlandı'

log fonksiyonu her mesaja zaman bilgisi ekliyor. Bir cron işinin ne zaman çalıştığını araştırırken bu zaman damgası değerlidir. Çıktıyı sonradan journalctl veya bir dosya üzerinden takip edebilirsiniz.

Döngüler, birden fazla dosya ya da sunucu üzerinde aynı işlemi yapmak için kullanılır:

for file in /var/log/*.log; do
    [[ -e "$file" ]] || continue
    printf '%s: ' "$file"
    wc -l < "$file"
done

Buradaki [[ -e "$file" ]] kontrolü, dizinde eşleşen dosya yoksa glob ifadesinin düz metin olarak kalmasını engeller. Bu ayrıntıyı atladığım eski bir script, olmayan /var/log/*.log dosyasını işlemeye çalışmıştı. Büyük bir arıza değildi ama gereksiz alarm üretti. İzleme sisteminde gürültü de bir arıza türüdür.

Gerçek bir otomasyon örneği: disk alarmı

Sunucuda disk alanı azaldığında yalnızca alarm göndermek yerine önce hangi dosya sisteminin dolduğunu, sonra da büyük dizinleri göstermek daha faydalıdır. Aşağıdaki örnek basit bir kontrol için yeterlidir:

#!/usr/bin/env bash

set -Eeuo pipefail

THRESHOLD=80
MOUNTPOINT="/"

usage=$(df -P "$MOUNTPOINT" | awk 'NR==2 {gsub("%", "", $5); print $5}')

if (( usage >= THRESHOLD )); then
    printf 'UYARI: %s kullanımı %s%% seviyesinde.n' "$MOUNTPOINT" "$usage" >&2
    printf 'En büyük dizinler:n' >&2
    du -xhd1 "$MOUNTPOINT" 2>/dev/null | sort -h | tail -n 8 >&2
    exit 1
fi

printf 'Disk normal: %s kullanım.n' "$usage"

df -P, çıktıyı daha düzenli ve script’ler için daha öngörülebilir hâle getirir. awk yüzde işaretini kaldırıp yalnızca sayıyı alıyor. du -x ise başka dosya sistemlerine geçmeden mevcut mount üzerinde kalıyor; bağlı bir uzak dosya sistemi yüzünden kontrolün beklenmedik biçimde uzamasını önlüyor.

Bir keresinde gece üçte /var bölümü dolmaya yaklaşmıştı. İlk refleksim servisi yeniden başlatmak oldu (evet, ben de o refleksi yıllarca törpüledim). Sonra ncdu ile baktığımda uygulamanın log rotation yapılandırmasının devre dışı kaldığını gördüm. Sorunu yeniden başlatmayla örtmek yerine logrotate kuralını düzelttim. Bash script burada tek başına çözüm değildi; doğru teşhisi tekrarlanabilir bir kontrole dönüştürmemi sağladı.

Cron ile zamanlanmış Bash görevleri

Bir script’i elle çalıştırmak başlangıç için yeterlidir. Düzenli kontrol veya yedekleme gerekiyorsa cron kullanılabilir. Önce script’i elle, mümkünse cron’un kullanacağı kullanıcıyla test edin:

sudo -u backup /usr/local/sbin/disk-kontrol.sh

Ardından ilgili kullanıcının crontab’ını açın:

crontab -e

Her 15 dakikada çalışacak bir satır şöyle görünür:

*/15 * * * * /usr/local/sbin/disk-kontrol.sh >> /var/log/disk-kontrol.log 2>&1

Cron ortamı etkileşimli shell ortamından daha sınırlıdır. PATH farklı olabilir, çalışma dizini beklediğiniz yer olmayabilir ve bazı ortam değişkenleri hiç bulunmayabilir. Kritik komutlarda mutlak yollar kullanmak veya script’in başında makul bir PATH tanımlamak bu yüzden iyi fikirdir.

PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
export PATH

Cron konusunda başımdan geçen derslerden biri, yanlış sunucuda yaptığım küçük bir zamanlama değişikliğinin etkisini fark etmemle ilgiliydi. Bir production shell’inde cron satırını düzenlemeye başlamıştım; tab tamamlamanın gösterdiği hostname, staging sandığım makinenin production olduğunu ortaya çıkardı. O günden beri komut çalıştırmadan önce hostname kontrol ediyor, kritik oturumlarda kırmızı prompt kullanıyorum. Otuz saniye sürüyor.

Çakışan çalışmaları engellemek

Yedekleme veya uzun süren rapor script’lerinde flock kullanabilirsiniz:

#!/usr/bin/env bash
set -Eeuo pipefail

exec 9>/run/lock/my-backup.lock
flock -n 9 || {
    printf 'Başka bir yedekleme zaten çalışıyor.n' >&2
    exit 1
}

printf 'Yedekleme başladı.n'
Uzun süren yedekleme komutları burada çalışır.

Script’in başında açılan dosya tanıtıcısı üzerinden kilit alınır. Script kapanınca kilit serbest kalır. Bu yaklaşım, aynı cron işinin iki kez çalışıp aynı hedefe eşzamanlı yazmasını önler.

Girdi doğrulama ve güvenli Bash alışkanlıkları

Bir Bash script’i root yetkisiyle çalışıyorsa kullanıcı girdisini doğrudan komuta eklemek risklidir. Özellikle eval kullanımı ve kullanıcıdan gelen metni shell kodu gibi çalıştırmak tehlikelidir.

Dosya yolu kabul eden basit bir script’te en azından şu kontrolleri yapın:

  • Beklenen argüman sayısını doğrulayın.
  • Dosya veya dizinin gerçekten var olduğunu kontrol edin.
  • Silme işlemlerinde hedef yolun boş olup olmadığına ayrıca bakın.
  • Değişkenleri çift tırnak içinde kullanın.
  • Silme veya taşıma öncesinde önce kuru çalıştırma seçeneği sunun.
  • Gerekmedikçe root kullanmayın.

Şu yaklaşım özellikle tehlikelidir:

rm -rf "$TARGET"/*

TARGET boş veya yanlış bir değere dönüşürse sonuç tahmin ettiğiniz gibi olmayabilir. Ben silme script’lerinde hedefi izin verilen üst dizinlerle karşılaştırmadan işlem yaptırmam:

if [[ -z "${TARGET:-}" || "$TARGET" == "/" ]]; then
    printf 'Güvenli olmayan hedef, işlem iptal edildi.n' >&2
    exit 1
fi

Bu kontrol tek başına kusursuz güvenlik sağlamaz. Yanlış değişken, eksik argüman ve aceleyle yapılan çalıştırmaların bir bölümünü yakalar. Üretim sunucusunda silme yapmadan önce hostname kontrol ederim. Tab tamamlamanın bana production hostname’ini göstermesi, yanlış sunucuda işlem yapmamı son saniyede engellemişti.

Bash script ile Python veya Ansible ne zaman ayrılır?

Bash her işi çözmez. Tek bir Linux sunucuda birkaç komutu birleştirmek, log ve dosya işlemleri yapmak, servis durumunu kontrol etmek için çok uygundur. Veri yapıları büyüdüğünde, karmaşık hata yönetimi gerektiğinde veya HTTP API’leri yoğun biçimde kullanıldığında Python daha okunaklı olabilir.

Birden fazla sunucunun kurulumunu aynı biçimde yapmak istiyorsanız Ansible daha doğru bir katman sunar. Benim ölçümüm basit: Elle iki kez yaptığım işi üçüncüde playbook’a taşırım. Tek satırlık bir paket kurulumunu sırf otomasyon adı geçsin diye YAML’a çevirmem.

İhtiyaç Daha uygun seçenek
Tek sunucuda dosya ve servis işlemleri Bash
Karmaşık veri işleme ve API entegrasyonu Python
Birden fazla sunucuda tekrarlanabilir yapılandırma Ansible
Dağıtım hattında küçük yardımcı görev Bash veya pipeline aracı

Linux sunucuyu ilk kurulumdan sonra hazırlamak için Yeni VPS Sunucuyu 30 Dakikada Canliya Alma Rehberi içindeki adımları bir Bash script’ine aktarmak cazip gelebilir. SSH anahtarı, firewall, kullanıcı ve paket kurulumu gibi adımlarda tekrar çalıştırılabilirlik tasarlanmadan yazılan script’ler ikinci çalıştırmada mevcut ayarları bozabilir. Her komutun zaten hazırlanmış bir sistemde nasıl davranacağını önce test edin.

Cloud-init de ilk açılış yapılandırmalarında Bash komutları çalıştırabilir. Bu noktada Cloud-Init Nedir? VPS Kurulumunu Otomatikleştirme içeriğindeki yaklaşım işinize yarayabilir. Bash betiğini doğrudan cloud-init içine gömmek yerine ayrı bir dosyaya koymak, sürümlemek ve loglamak genellikle daha temizdir.

Script’i test etmek ve izlemek

Bir script’in çalışması, doğru çalıştığı anlamına gelmez. Önce ayrı bir test VPS’inde veya benim yaptığım gibi Proxmox laboratuvarındaki geçici bir sanal makinede deneyin. Müşteri sunucusu deneme alanı değildir.

Debug için Bash’in izleme modunu kullanabilirsiniz:

bash -x ./disk-kontrol.sh

Bu komut çalıştırılan satırları gösterir. Hassas parolalar veya token’lar komut satırında bulunuyorsa çıktıyı paylaşmadan önce temizleyin. Gerekirse yalnızca belirli bölümü izlemek için set -x ve set +x kullanabilirsiniz.

Script’lerin çıktısını nereye yazdığınızı bilin. Cron altında standart çıktı çoğu sistemde e-posta olarak gönderilebilir; yanlış yapılandırmada posta kuyruğu büyüyebilir. Kritik script’lerde ya açıkça bir log dosyasına yönlendirme yaparım ya da systemd timer ve journal kullanırım.

Bir script için şu soruların cevabı net değilse henüz hazır değildir:

  • Başarılı çalıştığını nasıl anlayacağım?
  • Bir adım hata verirse sonraki adımlar çalışmalı mı?
  • Aynı anda iki kopya çalışırsa ne olur?
  • Log nerede tutulacak ve ne kadar saklanacak?
  • Geri alma veya yeniden çalıştırma davranışı nedir?

Basit görünür. Sunucuda beş yıl boyunca çalışan bir cron işinin sahibi olduğunuzda bu soruların her biri gerçek bir bakım işine dönüşür. Script’i bugün yazarken yarınki kendinize açıklama bırakın: değişken adlarını açık seçin, kritik adımlara yorum ekleyin ve önce staging ortamında çalıştırın.

Linux’ta script çalıştırırken kullanılan sudo ve diğer yönetim izinlerinin ne anlama geldiğini daha iyi kavramak için [admin ne demek] rehberime de göz atabilirsiniz; burada admin hesabının görevlerini ve yetkilerini sade bir dille açıklıyorum.

Sık Sorulan Sorular

Bash script ne için kullanılır?

Linux’ta komutları sıraya koymak, dosya işlemlerini otomatikleştirmek, servis kontrolü yapmak, yedekleme ve bakım görevlerini zamanlamak için kullanılır. Küçük ve orta ölçekli sistem yönetimi işlerinde hızlı bir çözüm sunar.

Bash script nasıl çalıştırılır?

Dosyaya çalıştırma izni verip ./script.sh komutunu kullanabilir veya doğrudan bash script.sh yazabilirsiniz. Dosyada Bash’e özgü söz dizimi varsa sh script.sh yerine Bash kullanmanız gerekir.

Bash script root olarak çalıştırılmalı mı?

Gerekmedikçe hayır. Yalnızca ihtiyaç duyulan komutlara sınırlı yetki vermek, script’teki bir hatanın etkisini azaltır. Root gerekiyorsa bile girdileri doğrulamak ve silme işlemlerine koruma eklemek gerekir.

Bash yerine Python veya Ansible ne zaman seçilmeli?

Karmaşık veri işleme ve API kullanımı arttığında Python, çok sayıda sunucuda tekrarlanabilir yapılandırma gerektiğinde Ansible daha uygun olabilir. Tek sunucuda birkaç güvenilir komutu çalıştırmak için Bash hâlâ daha az yükle iş görür.

Defne avatarı
Yazar

Defne

vps.tc blog yazarı. Sistem yönetimi, Linux ve hosting dünyası üzerine yazıyor.