Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
İlk Bash Script'i: Shebang, Çalıştırma İzni, Exit Code ve Ne Zaman Script Yazmamalı
Bir Bash script'i shebang satırıyla yorumlayıcısını seçer, çalıştırma izniyle çalışır ve çağıranla exit code üzerinden konuşur. Bookstore API'sinin health endpoint'ini kontrol eden 10 satırlık bir script'le shebang ve dash farkını, ./script.sh, bash ve source arasındaki farkı, exit code'ları, PATH'i, script iskeletini, CRLF tuzağını ve bir işin ne zaman Python, PowerShell ya da .NET 10 file-based app'e verilmesi gerektiğini gösteriyoruz.
Variable'lar, Quoting ve Expansion: Parametre Genişletme, Command Substitution, Array'ler ve Word Splitting Tuzağı
Bash'te variable'ı her zaman çift tırnak içinde kullanmak gerekir, çünkü tırnaksız değer word splitting ve globbing'e girer ve boşluklu bir dosya adı yanlış dosyanın silinmesine yol açabilir. Bash'in expansion sırasını, parametre genişletmeyi, command substitution ve aritmetiği, indexed ve associative array'leri, export'u ve ShellCheck'i Bookstore'un health script'i üzerinden gösteriyor, boş variable ile rm -rf ve macOS'taki Bash 3.2 tuzaklarını gerçek çıktılarla açıklıyoruz.
Koşullar ve Döngüler: if, [[ ]], case, for, while read ve Dosyalar Üzerinde Güvenle Dönmek
Bash'te if bir koşula değil bir komutun exit code'una bakar; bash script'lerinde [[ ]], sayılar için (( )), satır satır okumak için while IFS= read -r, dosya adları için glob ya da find -print0 kullanılır. Bookstore sunucusunda alt komutlu bir bookstore-ctl.sh ve son beş release'i tutan bir temizlik script'i yazarken glob sıralamasının canlı release'i silebildiği tuzağı, [ ] içindeki > ile oluşan dosyayı ve pipe'taki while döngüsünün kaybettiği sayacı gösteriyoruz.
Function'lar, Argümanlar ve Option Parse Etmek: $@, shift, getopts ve İyi Bir --help
Bash'te function veriyi stdout'tan, başarıyı exit code'dan döner; içindeki variable'lar local yazılmazsa global olur ve scope dinamiktir. Ortak function'ları source edilen bir kütüphanede toplayıp positional parametreler, shift, getopts ve uzun option'lar için while/case kalıbıyla Bookstore'un bookstore-deploy.sh -e staging -v 1.4.2 --dry-run arayüzünü, iyi bir --help metnini ve printf %q ile çalışan bir dry run'ı kuruyoruz.
Script'te Veri Akışı: Pipe, Redirection, Here-doc, Process Substitution ve xargs
Script'te stdout yalnız veri, stderr mesaj taşımalı; pipeline'ın exit code'u varsayılan olarak son komutunkidir, PIPESTATUS ve pipefail ile görünür olur. Bookstore'un deploy script'ine exec ve tee ile log dosyası, here-doc ile RELEASE dosyası ekliyor; pipe'tan beslenen döngünün kaybettiği variable'ı < <(...) ile kurtarıyor, xargs -0 -P ile paralel çalıştırıyor ve jq ile JSON rapor üretiyoruz.
Error Handling: set -euo pipefail'in Gerçek Davranışı, trap, Cleanup, Retry ve Kilit
set -e, sonucu koşul olarak kullanılan komutlarda ve bu koşullarda çağrılan function'ların içinde çalışmaz; local x=$(...), command substitution ve (( count++ )) da sürpriz yapar. Bookstore'un deploy script'ine set -Eeuo pipefail, call stack yazan bir ERR trap'i, yarım klasör bırakmayan EXIT trap'i, retry, timeout, flock ile tek deploy kilidi ve tekrar çalıştırılınca zarar vermeyen bir akış ekliyoruz.
Gerçek Script: Bookstore için Deploy ve Veritabanı Backup Script'i Yazmak
Güvenilir bir deploy script'i artifact'ı checksum ile doğrular, release'i current'ın dışında hazırlar, current'ı ln -sfn yerine mv -T ile atomik değiştirir ve health check başarısızsa önceki release'e döner. Bookstore için bu deploy'u, secret'ları argüman yerine env dosyasından okuyan yapıyı ve SQL Server için doğrulamalı, rotasyonlu, systemd timer ile zamanlanan bir backup script'ini yazıyoruz.
Script'i Test Etmek ve Taşınabilir Kılmak: ShellCheck, shfmt, bats-core, CI ve macOS'taki Bash 3.2'den Bash 5.3'e
Bash script'leri ShellCheck ile lint edilir, shfmt ile biçimlenir ve bats-core ile, PATH'e konan stub'larla test edilir; üçü de CI'da her pull request'te çalışmalı. Bookstore'un deploy ve kütüphane testlerini yazıp GitHub Actions'a bağlıyor, aynı testleri macOS'taki Bash 3.2'de, Bash 5.3'te ve Ubuntu 26.04'ün Rust coreutils'inde koşturup taşınabilirliğin nerede kırıldığını gösteriyoruz.