Skip to content

Repository files navigation

DevOps Bash & Regex Mastery

Mühendislik Verimliligi · Sürdürülebilir Tasarim · Üretime Hazir Otomasyon



İçindekiler

  1. Bash Scripting Temelleri
  2. Değişkenler ve Veri Tipleri
  3. Kontrol Yapıları
  4. Döngüler ve İterasyon
  5. Diziler ve Gelişmiş Veri Yapıları
  6. Fonksiyonlar ve Kapsam
  7. Hata Yönetimi ve Çıkış Kodları
  8. Regular Expressions (Regex) Ustalığı
  9. Dosya İşlemleri ve Metin İşleme
  10. Pratik DevOps Senaryoları
  11. AI Agent Entegrasyon Kalıpları
  12. Mühendislik Verimliliği Prensipleri
  13. Sürdürülebilir Tasarım Kalıpları
  14. Referanslar

1. Bash Scripting Temelleri

1.1 Shebang Satırı (#!/bin/bash)

Shebang (#!), çekirdeğe hangi yorumlayıcının kullanılacağını söyleyen sihirli bir bayt dizisidir. Script'in ilk satırı olmak zorundadır — öncesinde boş satır olamaz.

#!/bin/bash
#!/usr/bin/env bash   # Taşınabilir — $PATH üzerinden arar
#!/bin/sh             # POSIX uyumlu (minimalist)
#!/usr/bin/env python3

En İyi Uygulama: Farklı sistemlerde bash'in farklı yollarda olabileceği göz önüne alındığında, her zaman #!/usr/bin/env bash kullanın.

1.2 Script'leri Çalıştırılabilir Yapma

chmod +x script.sh
chmod 755 script.sh    # rwxr-xr-x — script'ler için standart

1.3 Script'leri Çalıştırma

./script.sh            # Çalıştırma izni gerektirir
bash script.sh         # +x olmadan da çalışır
source script.sh       # (veya . script.sh) — mevcut kabukta çalıştırır

1.4 Temel Script Şablonu

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

# ---------------------------------------------------------------
# Script: template.sh
# Açıklama: Üretime hazir bash script şablonu
# Yazar: DevOps Mühendisi
# Kullanim: ./template.sh [secenekler]
# ---------------------------------------------------------------

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly TIMESTAMP="$(date +'%Y-%m-%d_%H-%M-%S')"
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"

# Loglama fonksiyonu
log() {
    local seviye="$1"
    shift
    echo "[${TIMESTAMP}] [${seviye}] $*" >&2
}

main() {
    log "BILGI" "Script başlatildi"
    # Ana mantik buraya
    log "BILGI" "Script tamamlandi"
}

main "$@"

1.5 Yorum Satırları

# Tek satirlik yorum

: '
Çok satirli
yorum
'

2. Değişkenler ve Veri Tipleri

2.1 Değişken Tanımlama ve Kullanımı

isim="Berat"            # = etrafinda boşluk OLMAZ
yas=30
readonly PI=3.14159     # Değiştirilemez sabit
local degisken="deger"  # Fonksiyon kapsaminda değişken
declare -i sayi=42      # Tam sayı olarak tanımla
declare -r SABIT=1      # Salt okunur (readonly ile aynı)
declare -a dizi=()       # Dizi
declare -A harita=()     # İlişkisel dizi (hash map)

2.2 Değişken İkame (Substitution)

echo "$isim"            # Basit ikame — HER ZAMAN TIRNAK İÇİNE ALIN
echo "${isim}"          # Süslü parantez — belirsizliği önler
echo "${isim:-varsayilan}" # Tanımlı değilse varsayılan değer
echo "${isim:=varsayilan}" # Tanımlı değilse ata ve kullan
echo "${isim:?hata}"    # Tanımlı değilse hata ver
echo "${isim:+alternatif}" # Tanımlıysa alternatif değer
echo "${#isim}"         # String uzunluğu
echo "${isim:0:3}"      # Alt string (konum, uzunluk)
echo "${isim//e/a}"     # Tüm 'e' karakterlerini 'a' ile değiştir
echo "${isim^^}"        # Büyük harfe çevir (bash 4+)
echo "${isim,,}"        # Küçük harfe çevir (bash 4+)

2.3 Özel Değişkenler

Değişken Amaç
$0 Script adı
$1$9 Konumsal parametreler (argümanlar)
${10} 10. argüman (>9 için süslü parantez şart)
$# Argüman sayısı
$@ Tüm argümanlar (dizi benzeri, her biri ayrı)
$* Tüm argümanlar (tek string)
$? Son komutun çıkış durumu
$$ Mevcut işlem PID'si
$! Son arkaplan işleminin PID'si
$- Mevcut kabuk bayrakları
$_ Önceki komutun son argümanı
$LINENO Mevcut satır numarası
$SECONDS Script çalışma süresi (saniye)
$RANDOM Rastgele tamsayı 0–32767
$REPLY Varsayılan read değişkeni

2.4 Kullanıcıdan Veri Okuma

read -p "Adınızı girin: " isim
read -s -p "Şifre: " sifre     # Sessiz (ekrana yazılmaz)
read -t 5 -p "Hızlı cevap: " cevap   # 5 saniye zaman aşımı
read -n 1 -p "E/H: " onay      # Tek karakter, Enter gerekmez
read -a dizi -p "Sayılar: "    # Diziye oku

2.5 Aritmetik İşlemler

# Tamsayı aritmetiği — 3 eşdeğer sözdizimi:
sonuc=$(( 5 + 3 ))            # Modern POSIX
sonuc=$[ 5 + 3 ]              # Eski (kullanmayın)
let "sonuc = 5 + 3"           # let anahtar kelimesi

# Operatörler:
# +, -, *, /, % (mod), ** (üstel)
# +=, -=, *=, /=, %=
# ++, -- (artırım/azaltım)
# &, |, ^, ~, <<, >> (bit düzeyinde)

# Ondalıklı sayı — harici araçlar gerekli:
sonuc=$(echo "scale=2; 5/3" | bc)
sonuc=$(awk 'BEGIN { printf "%.2f", 5/3 }')

# Aritmetik karşılaştırma:
(( 5 > 3 )) && echo "doğru"
(( sonuc++ ))

2.6 Tırnak Kullanım Kuralları

degisken="hello world"

echo "$degisken"       # "hello world" — değişken genişletilir
echo '$degisken'       # $degisken — literal string (güçlü tırnak)
echo "\$degisken"      # $degisken — kaçırılmış (zayıf tırnak)
echo `date`            # date komutunu çalıştırır (ters tırnak — kullanmayın)
echo "$(date)"         # date komutunu çalıştırır (modern — tercih edin)

Altın Kural: Değişken genişletmelerini her zaman çift tırnak içine alın ("$degisken"). Bu, kelime bölünmesini (word-splitting) ve glob genişlemesini önler. Tırnaksız $degisken, bash hatalarının 1 numaralı kaynağıdır.


3. Kontrol Yapıları

3.1 If/Else Koşullu İfadeler

if [[ koşul ]]; then
    # komutlar
elif [[ diğer_koşul ]]; then
    # komutlar
else
    # komutlar
fi

Her zaman [[ ]] (çift köşeli parantez) kullanın, [ ] (tek köşeli parantez) veya test yerine. Çift köşeli parantezler bash'in yerleşik yapılarıdır ve daha fazla özellik sunar, daha az sürprizle karşılaşırsınız.

3.2 Dosya Test Operatörleri

[[ -f "$dosya" ]]    # Dosya var ve normal bir dosya
[[ -d "$dizin" ]]    # Dizin var
[[ -e "$yol" ]]      # Yol var
[[ -s "$dosya" ]]    # Dosya var ve boş değil
[[ -L "$dosya" ]]    # Dosya sembolik bağ
[[ -r "$dosya" ]]    # Dosya okunabilir
[[ -w "$dosya" ]]    # Dosya yazılabilir
[[ -x "$dosya" ]]    # Dosya çalıştırılabilir
[[ -O "$dosya" ]]    # Mevcut kullanıcıya ait
[[ -G "$dosya" ]]    # Mevcut gruba ait
[[ "$d1" -nt "$d2" ]]  # d1, d2'den daha yeni
[[ "$d1" -ot "$d2" ]]  # d1, d2'den daha eski

3.3 String Test Operatörleri

[[ -z "$str" ]]         # String boş (uzunluk sıfır)
[[ -n "$str" ]]         # String dolu (uzunluk sıfır değil)
[[ "$str1" == "$str2" ]] # Stringler eşit
[[ "$str1" != "$str2" ]] # Stringler eşit değil
[[ "$str1" =~ kalıp ]]   # Regex eşleşmesi (GENİŞLETİLMİŞ)
[[ "$str1" < "$str2" ]]  # Sözlüksel olarak küçük
[[ "$str1" > "$str2" ]]  # Sözlüksel olarak büyük
[[ "$str" == *"alt"* ]]  # Joker karakter (alt string içerir)
[[ "$str" == önek* ]]    # Önek ile başlar
[[ "$str" == *sonek ]]   # Sonek ile biter

3.4 Sayısal Karşılaştırma

[[ "$a" -eq "$b" ]]   # Eşit
[[ "$a" -ne "$b" ]]   # Eşit değil
[[ "$a" -lt "$b" ]]   # Küçük
[[ "$a" -le "$b" ]]   # Küçük veya eşit
[[ "$a" -gt "$b" ]]   # Büyük
[[ "$a" -ge "$b" ]]   # Büyük veya eşit

# (( )) içinde de geçerlidir:
(( a == b ))
(( a < b ))
(( a >= b ))

3.5 Mantıksal Operatörler

[[ koşul1 && koşul2 ]]    # VE
[[ koşul1 || koşul2 ]]    # VEYA
[[ ! koşul ]]             # DEĞİL

3.6 Case İfadesi

case "$deger" in
    basla|başlat)
        echo "Başlatılıyor..."
        ;;
    dur|durdur)
        echo "Durduruluyor..."
        ;;
    yeniden|restart)
        echo "Yeniden başlatılıyor..."
        ;;
    [0-9][0-9])
        echo "İki basamaklı sayı"
        ;;
    *.txt)
        echo "Metin dosyası"
        ;;
    "")
        echo "Boş string"
        ;;
    *)
        echo "Varsayılan durum — diğer her şey"
        exit 1
        ;;
esac

4. Döngüler ve İterasyon

4.1 For Döngüleri

# C-tarzı
for (( i=0; i<10; i++ )); do
    echo "$i"
done

# Liste-tarzı
for meyve in elma armut muz; do
    echo "$meyve"
done

# Aralık (bash 3+)
for i in {1..10}; do
    echo "$i"
done

# Aralık adımlı
for i in {0..20..2}; do
    echo "$i"
done

# Komut çıktısı
for dosya in $(ls *.txt); do      # HATA: boşlukta kelime bölünmesi
for dosya in *.txt; do             # DOĞRU: glob genişlemesi güvenlidir
for dosya in /var/log/*.log; do   # En iyisi: tam yol glob

4.2 While Döngüleri

# Sayaç döngüsü
sayac=0
while [[ $sayac -lt 10 ]]; do
    echo "$sayac"
    (( sayac++ ))
done

# Dosyayı satır satır oku (EN İYİ yöntem)
while IFS= read -r satir; do
    echo "$satir"
done < "girdi.txt"

# Komut çıktısından oku
bazi_komut | while read -r satir; do
    echo "$satir"
done

# Sonsuz döngü break ile
while true; do
    read -p "Komut girin: " komut
    [[ "$komut" == "çık" ]] && break
done

4.3 Until Döngüleri

sayac=0
until [[ $sayac -ge 10 ]]; do
    echo "$sayac"
    (( sayac++ ))
done

# Servis ayağa kalkana kadar bekle
until curl -sf http://localhost:8080/saglik; do
    echo "Servis bekleniyor..."
    sleep 2
done

4.4 Döngü Kontrolü

break       # Döngüden hemen çık
break N     # N seviye iç içe döngüden çık
continue    # Sonraki iterasyona atla
continue N  # N. döngünün sonraki iterasyonuna atla

4.5 Select Döngüsü (Etkileşimli Menüler)

PS3="Bir seçenek seçin: "
secenekler=("Başlat" "Durdur" "Yeniden Başlat" "Çık")

select secim in "${secenekler[@]}"; do
    case "$secim" in
        "Başlat")          echo "Başlatılıyor..." ;;
        "Durdur")          echo "Durduruluyor..." ;;
        "Yeniden Başlat")  echo "Yeniden başlatılıyor..." ;;
        "Çık")             break ;;
        *)                 echo "Geçersiz seçenek" ;;
    esac
done

5. Diziler ve Gelişmiş Veri Yapıları

5.1 İndeksli Diziler

# Tanımlama
dizi=("elma" "armut" "kiraz")
dizi[3]="hurma"
declare -a meyveler=()

# İndeksleme
echo "${dizi[0]}"        # İlk eleman
echo "${dizi[-1]}"       # Son eleman (bash 4.3+)
echo "${dizi[@]}"        # Tüm elemanlar
echo "${dizi[*]}"        # Tüm elemanlar tek string
echo "${#dizi[@]}"       # Dizi uzunluğu
echo "${!dizi[@]}"       # Tüm indeksler (0, 1, 2, ...)

# Dilimleme
echo "${dizi[@]:1:2}"    # İndeks 1'den başla, 2 eleman al

# Eleman Ekleme/Değiştirme
dizi+=("mürver")
dizi[1]="yaban mersini"
unset dizi[2]            # Eleman sil (boşluk bırakır)

# Döngü
for eleman in "${dizi[@]}"; do
    echo "$eleman"
done

5.2 İlişkisel Diziler (Hash Map) — Bash 4+

declare -A yapilandirma
yapilandirma=(
    ["sunucu"]="localhost"
    ["port"]=8080
    ["kullanici"]="admin"
)

echo "${yapilandirma[sunucu]}"       # localhost
echo "${yapilandirma[@]}"            # Tüm değerler
echo "${!yapilandirma[@]}"           # Tüm anahtarlar
echo "${#yapilandirma[@]}"           # Kayıt sayısı

for anahtar in "${!yapilandirma[@]}"; do
    echo "$anahtar => ${yapilandirma[$anahtar]}"
done

5.3 Yaygın Dizi Kalıpları

# String'i diziye böl
IFS=',' read -ra parcaciklar <<< "a,b,c,d"

# Diziyi string'e birleştir
birlestir() {
    local IFS="$1"
    shift
    echo "$*"
}
sonuc=$(birlestir "," "${dizi[@]}")

# Dizi elemanlarını dönüştür
ikile=()
for deger in "${orijinal[@]}"; do
    ikile+=("$(( deger * 2 ))")
done

# Eleman dizide var mı kontrol et
dizide_mi() {
    local aranan="$1"
    shift
    for eleman; do
        [[ "$eleman" == "$aranan" ]] && return 0
    done
    return 1
}

6. Fonksiyonlar ve Kapsam

6.1 Fonksiyon Tanımlama

# Stil 1 (POSIX uyumlu)
fonksiyonum() {
    echo "Merhaba fonksiyonum'dan"
}

# Stil 2 (bash'e özel)
function fonksiyonum {
    echo "Merhaba fonksiyonum'dan"
}

# Stil 3 (karma — en okunabilir)
function fonksiyonum() {
    echo "Merhaba fonksiyonum'dan"
}

6.2 Fonksiyon Argümanları

selamla() {
    local isim="$1"
    local selam="${2:-Merhaba}"
    echo "$selam, $isim!"
}

selamla "Dünya"         # Merhaba, Dünya!
selamla "Ali" "Selam"   # Selam, Ali!

6.3 Dönüş Değerleri

# Çıkış kodu döndür (0–255)
cift_mi() {
    [[ $(( $1 % 2 )) -eq 0 ]] && return 0 || return 1
}

if cift_mi 42; then
    echo "Çift"
fi

# stdout üzerinden veri döndür ($() ile yakala)
tarih_al() {
    date +'%Y-%m-%d'
}
bugun=$(tarih_al)

# Global değişkenle veri döndür
sonuc=""
hesapla() {
    sonuc=$(( $1 * $2 ))
}

6.4 Fonksiyon En İyi Uygulamaları

# Değişkenleri her zaman yerelleştirin
dosya_isle() {
    local dosya="$1" satir sayac=0

    while IFS= read -r satir; do
        (( sayac++ ))
    done < "$dosya"

    echo "$sayac"
}

# Kendini belgeleyen fonksiyonlar
#
# Kullanım: dosya_yedekle <kaynak_yol> [hedef_dizin]
#   kaynak_yol:      Dosyanın mutlak yolu
#   hedef_dizin:     Yedek dizini (varsayılan: /tmp/backup)
# Döndürür: 0 başarılı, 1 başarısız
dosya_yedekle() {
    local kaynak="$1"
    local hedef="${2:-/tmp/backup}"
    # ...
}

# Fonksiyon kütüphanesi yükle
source /usr/local/lib/bash-lib.sh

6.5 Fonksiyon Kütüphaneleri

# lib/loglama.sh
log_bilgi()  { echo "[BILGI]  $(date '+%H:%M:%S') $*" >&2; }
log_uyari()  { echo "[UYARI]  $(date '+%H:%M:%S') $*" >&2; }
log_hata()   { echo "[HATA] $(date '+%H:%M:%S') $*" >&2; }

# Ana script'te:
source "$(dirname "$0")/lib/loglama.sh"

7. Hata Yönetimi ve Çıkış Kodları

7.1 Kutsal Üçleme: set -euo pipefail

set -e          # İlk hatada çık (errexit)
set -u          # Tanımsız değişkenleri hata kabul et (nounset)
set -o pipefail # Pipeline herhangi bir komut başarısız olursa başarısız

# Birleşik (her üretim script'inin başına koyun):
set -euo pipefail
Bayrak Etkisi Neden Kullanmalı?
-e Script komut hatasında çıkar Sessiz hataların zincirleme yayılmasını önler
-u Tanımsız değişkenlerde hata verir Yazım hatalarını yakalar, rm -rf $tanimsiz felaketlerini önler
-o pipefail Pipeline dönüş kodu = son sıfır olmayan çıkış Olmazsa false | true başarılı olur

7.2 Çıkış Kodu Sözleşmesi

exit 0    # Başarılı
exit 1    # Genel hata
exit 2    # Kabuk yerleşiklerinin yanlış kullanımı
exit 126  # Çalıştırılamayan komut
exit 127  # Komut bulunamadı
exit 128  # exit'e geçersiz argüman
exit 130  # Script Ctrl+C ile sonlandırıldı (128 + SIGINT)
exit 137  # Öldürüldü (SIGKILL)
exit 255  # Çıkış kodu aralık dışı

7.3 Trap İşleyicileri

# Çıkışta temizlik
temizlik() {
    rm -f /tmp/gecici_$$
    log "BILGI" "Temizlik tamamlandı"
}
trap temizlik EXIT

# SIGINT'i (Ctrl+C) yoksay
trap '' SIGINT SIGTERM

# Özel sinyal işleyici
sinyal_isleyici() {
    log "UYARI" "Sinyal alındı $1, nazikçe kapatılıyor..."
    exit 0
}
trap 'sinyal_isleyici SIGTERM' SIGTERM
trap 'sinyal_isleyici SIGINT'  SIGINT

# Hata ayıklama için trap
trap 'echo "$LINENO satirinda HATA (çıkış kodu: $?)"' ERR

7.4 Hata Yönetim Kalıpları

# Koruma (guard) cümleciği kalıbı
[[ -f "$yapilandirma_dosyasi" ]] || {
    echo "HATA: Yapılandırma dosyası bulunamadı: $yapilandirma_dosyasi" >&2
    exit 1
}

# Komut durumu kontrolü
if ! mkdir -p "$yedek_dizini"; then
    echo "HATA: Yedek dizini oluşturulamadı" >&2
    exit 1
fi

# Beklenen hatalar için || true kullan
rm -f "$kilit_dosyasi" || true   # Dosya yoksa sorun değil

# Strict modu geçici olarak devre dışı bırak
set +e
hatan_olabilecek_komut
durum=$?
set -e

# Kapsamlı hata yönetimi için alt kabuk kullan
(
    set -e
    riskli_is_leri_yap
)
echo "Alt kabuk başarısız olsa bile devam ediyoruz"

8. Regular Expressions (Regex) Ustalığı

8.1 Temel Kavramlar

Regular expression (düzenli ifade), bir arama kalıbını tanımlayan karakter dizisidir. Regex "eşleşme" temelinde çalışır — kod çalıştırmaz, metin kalıplarını tanımlar.

8.2 Literal Karakterler

Çoğu karakter regex'te kendisiyle eşleşir:

merhaba    → "merhaba" metnini herhangi bir yerde eşleştirir

8.3 Meta-Karakterler (Regex Gücünün Özü)

Meta-kar Adı Eşleştiği
. Nokta Yeni satır hariç herhangi bir karakter
^ Şapka Satır/string başlangıcı
$ Dolar Satır/string sonu
* Yıldız/Kleene Önceki elemanın sıfır veya daha fazlası
+ Artı Önceki elemanın bir veya daha fazlası
? Soru Önceki elemanın sıfır veya bir tane (opsiyonel)
\ Ters bölü Kaçış karakteri / literalleri meta'ya çevirir
| Boru Alternatif (VEYA)
() Parantez Gruplama ve yakalama
[] Köşeli parantez Karakter sınıfı (küme)
{} Süslü parantez Miktar belirleyici

8.4 Karakter Sınıfları (Kümeler)

[abc]       # a, b veya c
[a-z]       # Herhangi bir küçük harf
[A-Z]       # Herhangi bir büyük harf
[0-9]       # Herhangi bir rakam
[a-zA-Z]    # Herhangi bir harf
[a-zA-Z0-9] # Herhangi bir alfanümerik
[^abc]      # a, b veya c DEĞİL (olumsuzlama)
[^0-9]      # Rakam DEĞİL

# Ön tanımlı sınıflar (POSIX):
[[:alnum:]]  # Alfanümerik: [a-zA-Z0-9]
[[:alpha:]]  # Alfabetik: [a-zA-Z]
[[:digit:]]  # Rakam: [0-9]
[[:lower:]]  # Küçük harf: [a-z]
[[:upper:]]  # Büyük harf: [A-Z]
[[:space:]]  # Boşluk karakteri: space, tab, newline
[[:blank:]]  # Sadece space ve tab
[[:punct:]]  # Noktalama
[[:print:]]  # Yazdırılabilir karakterler
[[:graph:]]  # Görünür karakterler (boşluksuz)
[[:cntrl:]]  # Kontrol karakterleri

8.5 Çapalar (Anchors)

^Merhaba      # Satır "Merhaba" ile başlar
Dünya$        # Satır "Dünya" ile biter
^Sadece Bu$   # Tam satır eşleşmesi
^$            # Boş satır

8.6 Miktar Belirleyiciler (Quantifiers)

colou?r       # "color" veya "colour" (o opsiyonel)
go*gle        # "ggle", "gogle", "google", "gooogle"... (sıfır veya daha fazla)
go+gle        # "gogle", "google", "gooogle"... (bir veya daha fazla)
[0-9]{3}      # Tam 3 rakam
[0-9]{3,}     # 3 veya daha fazla rakam
[0-9]{2,4}    # 2 ila 4 rakam
[0-9]{,3}     # 0 ila 3 rakam (nadir)

8.7 Açgözlü (Greedy) vs Tembel (Lazy) Eşleştirme

.*            # Açgözlü — MÜMKÜN OLDUĞUNCA FAZLA eşleştirir
.*?           # Tembel — MÜMKÜN OLDUĞUNCA AZ eşleştirir

Metin: <h1>Başlık</h1><p>Gövde</p>
<.*>          # Tüm stringi eşleştirir (açgözlü)
<.*?>         # "<h1>", "</h1>", "<p>", "</p>" ayrı ayrı (tembel)

8.8 Gruplama ve Yakalama

(abc)+        # "abcabcabc"  grubu miktarla
(https?://)?  # Opsiyonel protokol grubu

# Geri referanslar
(["']).*\1    # "merhaba" veya 'dünya' ile eşleşir (aynı tırnak)

# Adlandırılmış gruplar (PCRE)
(?<adi>kalip) # .NET, Perl 5.10+

# Yakalama yapmayan gruplar
(?:kalip)     # Gruplar ama yakalamaz

8.9 Gelişmiş Regex Yapıları

İleriye Bakma (Lookahead) / Geriye Bakma (Lookbehind)

foo(?=bar)    # Olumlu ileri bakış: "foo" sadece arkasından "bar" geliyorsa
foo(?!bar)    # Olumsuz ileri bakış: "foo" sadece arkasından "bar" gelmiyorsa
(?<=foo)bar   # Olumlu geri bakış: "bar" sadece öncesinde "foo" varsa
(?<!foo)bar   # Olumsuz geri bakış: "bar" sadece öncesinde "foo" yoksa

Önemli: grep -P GNU grep'te PCRE'yi etkinleştirir. macOS grep BSD'dir — PCRE için ggrep veya pcre2grep kullanın.

8.10 Grep Komutunda Ustalık

# Temel kullanım
grep "kalıp" dosya.txt
grep "hata" /var/log/syslog

# Yaygın seçenekler
grep -i "uyari" log.txt        # Büyük/küçük harf duyarsız
grep -r "TODO" src/            # Özyinelemeli
grep -l "fonksiyon" *.sh       # Sadece dosya adlarını listele
grep -c "hata" log.txt          # Eşleşme sayısı
grep -n "kalıp" dosya.txt      # Satır numaralarını göster
grep -v "hariç" dosya.txt      # Ters eşleştir
grep -w "tam" dosya.txt        # Tam kelime eşleşmesi
grep -x "tam satır" dosya.txt  # Tam satır eşleşmesi
grep -A 3 "kalıp" dosya.txt    # Eşleşmeden SONRA 3 satır
grep -B 2 "kalıp" dosya.txt    # Eşleşmeden ÖNCE 2 satır
grep -C 5 "kalıp" dosya.txt    # Eşleşme etrafında 5 satır

# Genişletilmiş regex (ERE) — -E kullan
grep -E "^[0-9]{3}-[0-9]{4}$" dosya.txt

# Perl uyumlu regex (PCRE)
grep -P "\d{3}-\d{4}" dosya.txt   # BSD grep'te çalışmaz

# Pratik örnekler
grep -E "(HATA|KRITIK)" uygulama.log
grep -oE "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" erisim.log | sort | uniq -c | sort -rn
grep -E "^[^#]" /etc/ssh/sshd_config    # Yorum olmayan satırlar
grep -c "POST /api" erisim.log          # API çağrılarını say

8.11 Sed — Akış Düzenleyici

# Değiştirme
sed 's/eski/yeni/' dosya.txt            # Satırdaki ilk eşleşme
sed 's/eski/yeni/g' dosya.txt           # Tüm eşleşmeler (global)
sed 's/eski/yeni/2' dosya.txt           # Sadece ikinci eşleşme
sed 's/eski/yeni/gi' dosya.txt          # Global + büyük/küçük harf duyarsız
sed 's/\(parca1\)\(parca2\)/\2\1/' dosya.txt  # Geri referans

# Yerinde düzenleme
sed -i 's/eski/yeni/g' dosya.txt        # GNU sed
sed -i '' 's/eski/yeni/g' dosya.txt     # BSD sed (macOS)

# Satır adresleme
sed '3s/foo/bar/' dosya.txt             # Sadece 3. satır
sed '5,10s/foo/bar/' dosya.txt          # 5–10. satırlar
sed '/hata/s/foo/bar/' dosya.txt        # "hata" ile eşleşen satırlar
sed '/^$/d' dosya.txt                   # Boş satırları sil
sed -n '10,20p' dosya.txt               # 10–20. satırları yazdır

# Çoklu komut
sed -e 's/foo/bar/' -e 's/baz/qux/' dosya.txt
sed 's/foo/bar/; s/baz/qux/' dosya.txt

8.12 Awk — Kalıp Tarama ve İşleme

# Alan çıkarma
awk '{print $1, $NF}' dosya.txt         # İlk ve son alan
awk -F: '{print $1, $3}' /etc/passwd   # Özel alan ayracı

# Kalıp eşleştirme
awk '/hata/ {print NR, $0}' log.txt
awk '$3 > 100 {print $1, $3}' veri.txt

# Yerleşik değişkenler
awk '{print NR, NF, $0}' dosya.txt     # Satır no, alan sayısı, tüm satır
awk 'NR > 1 {print}' dosya.txt         # Başlık satırını atla

# BEGIN/END blokları
awk 'BEGIN {toplam=0} {toplam+=$1} END {print "Toplam:", toplam}' sayilar.txt

# Formatlı çıktı
awk '{printf "%-20s %5d\n", $1, $2}' dosya.txt

# Çoklu koşul
awk '$3 >= 90 && $3 <= 100 {print}' notlar.txt

9. Dosya İşlemleri ve Metin İşleme

9.1 Dosya Okuma

# Satır satır (güvenilir — boşlukları korur, tüm karakterleri işler)
while IFS= read -r satir; do
    echo "$satir"
done < "dosya.txt"

# Dosya tanıtıcısı ile (alt kabuk sorunlarını önler)
while IFS= read -r -u3 satir; do
    echo "$satir"
done 3< "dosya.txt"

# Tüm dosyayı değişkene oku
icerik=$(<dosya.txt)

# Belirli satırları oku
mapfile -t satirlar < dosya.txt        # Tüm satırları diziye oku (bash 4+)
satir=$(sed -n '5p' dosya.txt)         # 5. satır

9.2 Dosyaya Yazma

echo "metin" > dosya.txt             # Üzerine yaz (truncate)
echo "metin" >> dosya.txt            # Ekle

cat > dosya.txt << EOF
Çok satırlı
içerik
EOF

cat >> dosya.txt << EOF
Eklenen içerik
EOF

# Girintili heredoc (sekmeleri temizle)
cat >> dosya.txt <<- EOF
    Girintili içerik
EOF

# Değişken genişletmeyi engelleyen heredoc
cat >> dosya.txt << 'EOF'
$HOME burada genişlemez
EOF

9.3 Dosya Tanıtıcıları

exec 3< girdi.txt      # FD 3'te okuma için aç
exec 4> cikti.txt      # FD 4'te yazma için aç
exec 5>> ekle.txt      # FD 5'te ekleme için aç
exec 6<> okumayaz.txt  # FD 6'da okuma-yazma için aç

while read -u3 satir; do
    echo "$satir" >&4
done
exec 3<&-              # FD 3'ü kapa
exec 4>&-              # FD 4'ü kapa

9.4 Yaygın Dosya İşlemleri

# Dosyanın içeriği var mı?
[[ -s "$dosya" ]] && echo "İçerik var" || echo "Boş"

# Geçici dosyalar
gecici=$(mktemp /tmp/script_XXXXX)
trap 'rm -f "$gecici"' EXIT

# Geçici dizin
gecici_dizin=$(mktemp -d /tmp/script_dizini_XXXXX)

# Kilit dosyası
kilit="/var/run/script.lock"
exec 200>"$kilit"
flock -n 200 || { echo "Script zaten çalışıyor"; exit 1; }

9.5 Yönlendirme Derinlemesine

komut > dosya       # stdout → dosya
komut 2> dosya      # stderr → dosya
komut &> dosya      # stdout ve stderr → dosya
komut > dosya 2>&1  # Klasik: stdout sonra stderr → dosya
komut >> dosya 2>&1 # İkisini de ekle

komut < dosya       # stdin dosyadan
komut <<< "string"  # stdin string'den (here-string)

komut > /dev/null   # stdout'u yok say
komut 2>&-          # stderr'i kapa

# Grup çıktısı
{
    komut1
    komut2
} > dosya

# Süreç ikamesi (process substitution)
diff <(ls dizin1) <(ls dizin2)
while read -r satir; do ... done < <(komut)

10. Pratik DevOps Senaryoları

10.1 Disk Alanı İzleme

ESIK=80
df -h | awk 'NR>1 {gsub(/%/,"",$5); if($5 > ESIK) print $0}'

10.2 Log Döndürme (Rotation)

# Log'ları arşivle ve sıfırla
log_dosyasi="/var/log/uygulama.log"
max_boyut=$(( 100 * 1024 * 1024 ))  # 100MB

if [[ -f "$log_dosyasi" ]] && [[ $(stat -f%z "$log_dosyasi") -gt $max_boyut ]]; then
    gzip -c "$log_dosyasi" > "${log_dosyasi}.$(date +%Y%m%d-%H%M%S).gz"
    : > "$log_dosyasi"    # Sıfırla (silme, truncate)
fi

10.3 Yedekleme Otomasyonu

yedek_dizinleri=("/etc" "/home" "/var/www")
yedek_tabani="/yedek/$(date +%Y/%m)"
mkdir -p "$yedek_tabani"

for dizin in "${yedek_dizinleri[@]}"; do
    yedek_adi="$(basename "$dizin")_$(date +%Y%m%d_%H%M%S).tar.gz"
    tar -czf "$yedek_tabani/$yedek_adi" "$dizin"
done

10.4 Sistem Sağlık Kontrolü

# CPU Yükü
cpu_bos=$(top -bn1 | grep "Cpu(s)" | awk '{print $8}' | cut -d'.' -f1)
[[ $cpu_bos -lt 20 ]] && echo "KRITIK: CPU boşluk %20'nin altında"

# Bellek Kullanımı
bellek_bos=$(free -m | awk '/^Mem:/ {print $4}')
[[ $bellek_bos -lt 500 ]] && echo "KRITIK: Boş bellek 500MB altında"

# Disk I/O
iostat -x 1 2 | tail -n +4 | awk '$1 ~ /^[a-z]/ {if ($14 > 90) print $1 " kullanım > %90"}'

# Servis Durumu
servis_kontrol() {
    systemctl is-active --quiet "$1" || echo "Servis $1 çalışmıyor"
}

10.5 Konteyner Sağlık Kontrolü

#!/bin/bash
set -euo pipefail

konteyner_adi="$1"
zaman_asimi="${2:-30}"

for (( i=0; i<zaman_asimi; i++ )); do
    if docker inspect --format '{{.State.Health.Status}}' "$konteyner_adi" 2>/dev/null | grep -q "healthy"; then
        echo "Konteyner $konteyner_adi sağlıklı"
        exit 0
    fi
    sleep 1
done

echo "Zaman aşımı: Konteyner $konteyner_adi ${zaman_asimi}s içinde sağlıklı olmadı"
exit 1

11. AI Agent Entegrasyon Kalıpları

11.1 AI Tüketimi İçin Yapılandırılmış Çıktı

AI ajanları yapılandırılmış veri tüketir. Script'leri güvenilir JSON ayrıştırması için tasarlayın:

#!/bin/bash
set -euo pipefail

rapor_olustur() {
    local sunucu_adi="$(hostname)"
    local calisma_suresi="$(uptime -p)"
    local cpu_yuku="$(uptime | awk -F'load average:' '{print $2}' | tr -d ' ')"

    jq -n \
        --arg sunucu "$sunucu_adi" \
        --arg sure "$calisma_suresi" \
        --arg cpu "$cpu_yuku" \
        '{hostname: $sunucu, uptime: $sure, cpu_load: $cpu}'
}

rapor_olustur

11.2 Idempotent (Tekrarlanabilir) İşlemler

AI ajanları işlemleri tekrarlayabilir. Script'ler idempotent olmalıdır (birden çok çalıştırmada güvenli):

kullanici_olustur() {
    local kullanici_adi="$1"

    if id "$kullanici_adi" &>/dev/null; then
        echo "Kullanıcı $kullanici_adi zaten var — atlanıyor"
        return 0
    fi

    useradd -m -s /bin/bash "$kullanici_adi"
    echo "Kullanıcı $kullanici_adi oluşturuldu"
}

11.3 Makine Tarafından Okunabilir Çıkış Kodları

AI ajanlarının script'lerden net sinyallere ihtiyacı vardır. Her zaman anlamlı çıkış kodları döndürün:

# 0: Başarılı / İşlem gerekmez
# 1: Geçici hata (tekrar denenebilir)
# 2: Kalıcı hata (tekrar deneme)
# 3: Idempotent atlama (zaten yapılmış)

yapilandirma_guncelle() {
    local dosya="$1"
    if [[ ! -f "$dosya" ]]; then
        return 2  # Kalıcı — yapılandırma dosyası yok
    fi
    # ... güncelleme mantığı ...
}

11.4 Durum Raporlama

AI ajanlarının sorgulayabileceği durum dosyaları sağlayın:

AI_DURUM_DIZINI="/var/lib/ai-agent"

durum_raporla() {
    local gorev_id="$1"
    local durum="$2"
    local mesaj="$3"

    mkdir -p "$AI_DURUM_DIZINI"
    cat > "$AI_DURUM_DIZINI/${gorev_id}.json" << EOF
{
    "task_id": "$gorev_id",
    "status": "$durum",
    "message": "$mesaj",
    "timestamp": "$(date -Iseconds)"
}
EOF
}

11.5 Olay Tetiklemeli (Event-Driven) İşlemler

Dosya sistemi olaylarına yanıt veren script'ler tasarlayın:

inotifywait -m -e create -e modify /var/spool/upload/ |
    while read -r dizin olaylar dosya; do
        /usr/local/bin/islemeyi-baslat.sh "$dizin/$dosya"
    done

11.6 Büyük Dil Modeli (LLM) ile Haberleşme

AI orkestratörü, LLM'lerle yapılandırılmış JSON şeması üzerinden haberleşir:

{
  "workflow": "gece_bakimi",
  "trigger": "cron_schedule",
  "tasks": [
    {
      "id": "saglik_kontrol",
      "type": "health_check",
      "timeout": 30,
      "depends_on": [],
      "on_success": "baslat_yedekleme",
      "on_failure": "bildirim_gonder"
    }
  ],
  "llm_context": {
    "model": "claude-3-opus",
    "max_tokens": 4000,
    "temperature": 0.1
  }
}

LLM'den gelen next_action alanı, orkestratörün bir sonraki adımını belirler. Bu sayede AI, iş akışını dinamik olarak yönlendirebilir.


12. Mühendislik Verimliliği Prensipleri

12.1 DRY Prensibi (Kendini Tekrarlama)

# KÖTÜ — tekrarlanan mantık
echo "[$(date +'%Y-%m-%d %H:%M:%S')] İşlem A başlatılıyor" >> /var/log/uygulama.log
./islem_a.sh
echo "[$(date +'%Y-%m-%d %H:%M:%S')] İşlem B başlatılıyor" >> /var/log/uygulama.log
./islem_b.sh

# İYİ — fonksiyon çıkarma
log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >> /var/log/uygulama.log
}
log "İşlem A başlatılıyor"
./islem_a.sh
log "İşlem B başlatılıyor"
./islem_b.sh

12.2 Erken Hata Bildirimi (Fail Fast)

Girdileri ve ön koşulları işlemin başında doğrulayın, yarısında değil:

#!/bin/bash
set -euo pipefail

# Önce TÜM girdileri doğrula
[[ $# -ge 2 ]] || { echo "Kullanım: $0 <kullanici> <rol>"; exit 1; }
[[ -f "/etc/yapilandirma.json" ]] || { echo "Yapılandırma bulunamadı"; exit 1; }
command -v jq &>/dev/null || { echo "jq gerekli"; exit 1; }
[[ $EUID -eq 0 ]] || { echo "Root yetkisi gerekli"; exit 1; }

# Şimdi güvenle çalıştır

12.3 Idempotency (Tekrarlanabilirlik)

Bir script'in birden çok çalıştırılması, tek çalıştırılmasıyla aynı sonucu vermelidir:

# Idempotent: mkdir -p zaten idempotent
mkdir -p /yedek/gunluk

# Idempotent: Sil ve yeniden oluştur (dikkatli!)
rm -rf /tmp/calisma_dizini && mkdir -p /tmp/calisma_dizini

# Idempotent değil: Her çalıştırmada yeni satır ekler (KÖTÜ)
echo "kayit" >> /etc/hosts

# Idempotent: Sadece yoksa ekle (İYİ)
grep -q "kayit" /etc/hosts || echo "kayit" >> /etc/hosts

12.4 Modülerlik (Modularity)

Tek bir işi iyi yapan küçük, birleştirilebilir fonksiyonlar:

# Tek sorumluluklu fonksiyonlar
ip_dogrula() { ... }
port_kontrol() { ... }
uyari_gonder() { ... }
main() {
    local ip="$1"
    ip_dogrula "$ip" || exit 1
    port_kontrol "$ip" 80 || uyari_gonder "Port 80 kapalı: $ip"
}

12.5 Uzun Süren Görevlerde İlerleme Göstergesi

ilerleme_goster() {
    local mevcut="$1"
    local toplam="$2"
    local yuzde=$(( mevcut * 100 / toplam ))
    printf "\rİlerleme: [%-50s] %d%%" "$(printf '#%.0s' $(seq 1 $((yuzde/2))))" "$yuzde"
}

13. Sürdürülebilir Tasarım Kalıpları

13.1 Kendini Belgeleyen Script'ler

#!/usr/bin/env bash
#
# Ad:         deploy.sh
# Açıklama:   Kesintisiz dağıtım otomasyonu
# Kullanım:   ./deploy.sh <ortam> <surum>
#   ortam:      staging | production
#   surum:      Semantic version (örn. 2.1.4)
# Ön Koşullar:
#   - jq kurulu (brew install jq)
#   - SSH anahtarı hedef sunuculara yüklenmiş
#   - Docker registry kimlik doğrulaması
# Çıkış Kodları:
#   0 — Dağıtım başarılı
#   1 — Geçersiz argümanlar
#   2 — Ön kontrol başarısız
#   3 — Dağıtım başarısız (geri alındı)

13.2 Yapılandırma Dışsallaştırması

# config.sh (çalıştırılmaz, kaynak olarak yüklenir)
readonly APP_HOME="/opt/uygulamam"
readonly LOG_DIR="/var/log/uygulamam"
readonly YEDEK_DIR="/yedek/uygulamam"
readonly MAX_LOG_YAS=7          # Gün
readonly ALARM_EMAIL="ops@ornek.com"
readonly SLACK_WEBHOOK="https://hooks.slack.com/services/..."

# Yükle:
[[ -f "./config.sh" ]] && source "./config.sh"
[[ -f "/etc/uygulamam/config.sh" ]] && source "/etc/uygulamam/config.sh"

13.3 Nazik Bozulma (Graceful Degradation)

# Özellik tespiti, varsayım değil
if command -v jq &>/dev/null; then
    cikti_formatla() { jq -r "$@"; }
else
    cikti_formatla() { echo "jq kurulu değil — ham çıktı"; cat; }
fi

13.4 Seviyeli Loglama

declare -A LOG_SEVIYELERI=([DEBUG]=0 [BILGI]=1 [UYARI]=2 [HATA]=3)
LOG_SEVIYESI="${LOG_SEVIYESI:-BILGI}"

log() {
    local seviye="$1"
    shift
    [[ ${LOG_SEVIYELERI[$seviye]} -ge ${LOG_SEVIYELERI[$LOG_SEVIYESI]} ]] || return 0
    echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')] [$seviye] $*" >&2
}

13.5 Renkli Çıktı Standardı

readonly KIRMIZI='\033[0;31m'
readonly YESIL='\033[0;32m'
readonly SARI='\033[1;33m'
readonly MAVI='\033[0;34m'
readonly NC='\033[0m'  # Renk Yok

renklendir() {
    local renk="$1"
    shift
    echo -e "${renk}$*${NC}"
}

basarili() { renklendir "$YESIL" "[✓] $*"; }
hata()     { renklendir "$KIRMIZI" "[✗] $*" >&2; }
uyari()    { renklendir "$SARI" "[!] $*"; }
bilgi()    { renklendir "$MAVI" "[i] $*"; }

14. Referanslar

Video Kursları

Kaynak Konular
KodeKloud — Linux'ta Düzenli İfadeler Regex meta-karakterleri, grep, sed, awk, log analizi
TechWorld with Nana — Bash Scripting Eğitimi Bash temelleri, otomasyon, DevOps script'leri

Resmi Dokümantasyon

Regex Referansları


Mühendislik Verimliliği · Sürdürülebilir Tasarım · Üretime Hazır Otomasyon
github.com/BerattCelikk/DevOps-Bash-RegEx-Mastery

About

Comprehensive guide to DevOps, Bash scripting, and regex patterns for system automation

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages