Ders 20 / 24
Hata Yönetimi
Katı kip seçenekleri, erken çıkışın kapsamı ve istisnaları, tanımsız değişken denetimi, boru hattı kodu ve hata yakalama kancası.
İçindekiler
Betik doğru çıktı üretiyor, ama yalnızca her şey yolunda gittiğinde. Bir komut başarısız olduğunda rapor yarım kalıyor ve betiğin çıkış kodu bunu bildirmiyor. Tanımsız bir değişken sessizce boş dizgiye genişliyor. Boru hattının ortasındaki hata görünmüyor.
Kabuğun öntanımlı davranışı hataya karşı hoşgörülüdür: bir komut başarısız olsa da sonraki komut çalışır. Bu, etkileşimli kullanımda doğru bir seçimdir — yanlış yazılmış bir komut oturumu kapatmamalıdır. Betikte ise ters etki yapar.
Katı kip (strict mode), kabuğun bu hoşgörüsünü kısan seçenekler kümesidir. Bu ders seçenekleri tek tek ele alır; her birinin ne yakaladığını ve — daha önemlisi — ne yakalamadığını gösterir.
Erken Çıkış
set -e seçeneği, çıkış kodu sıfırdan farklı olan bir komuttan sonra kabuğu sonlandırır.
#!/usr/bin/env bash set -e echo "1: baslangic" false echo "2: BU SATIR YAZILMAZ"
1: baslangic
echo $?
1
Betik ikinci satıra ulaşmadan durdu ve başarısızlık kodunu dışarı taşıdı. Kazanç yalnızca kolaylık değildir: bir betiğin yarım çıktı üretip başarı bildirmesi, onu çağıran her sistemi yanıltır.
Erken Çıkışın İstisnaları
set -e bir komutun başarısızlığını her yerde ölümcül saymaz. İstisnalar mantıklıdır ama
sayıları çoktur ve bilinmezse yanlış güven verir.
#!/usr/bin/env bash set -e if false; then echo "a"; fi echo "1: kosulda basarisizlik betigi durdurmaz" false || echo "2: || solunda basarisizlik durdurmaz" false && echo "buraya gelinmez" echo "3: && solunda basarisizlik da durdurmaz" false | true echo "4: boru hattinin son komutu basarili ise durdurmaz" ! false echo "5: degillenmis komut durdurmaz" f() { false; echo "f devam etti"; } if f; then :; fi echo "6: kosulda cagrilan fonksiyon icinde set -e askiya alinir"
1: kosulda basarisizlik betigi durdurmaz 2: || solunda basarisizlik durdurmaz 3: && solunda basarisizlik da durdurmaz 4: boru hattinin son komutu basarili ise durdurmaz 5: degillenmis komut durdurmaz f devam etti 6: kosulda cagrilan fonksiyon icinde set -e askiya alinir
Altı istisnanın ilk beşi tasarım gereğidir: koşul olarak kullanılan bir komutun başarısızlığı bilgi taşır, hata değildir. Altıncısı en tehlikelisidir — bir koşulda çağrılan fonksiyonun tüm gövdesi boyunca erken çıkış askıya alınır ve gövdedeki gerçek hatalar görünmez olur.
Bu yüzden set -e tek başına bir güvence değildir. Kritik komutların kodları ayrıca
sınanmalı ya da bir hata kancası kurulmalıdır.
Tanımsız Değişken Denetimi
set -u seçeneği, tanımsız bir değişkenin genişletilmesini hata sayar.
#!/usr/bin/env bash set -u echo "kutuk: ${KUTUK}"
./u.sh: line 3: KUTUK: unbound variable
Bu seçenek, kabuk betiklerinde en yıkıcı hata sınıfını yakalar. rm -rf "$DIZIN/" satırı,
DIZIN tanımsızken rm -rf / hâline gelir — seçenek etkinken betik o satıra hiç
ulaşmaz.
Seçenek, öntanımlı değer gösterimlerini kullanmayı zorunlu kılar:
#!/usr/bin/env bash set -u echo "kutuk: ${KUTUK:-erisim.log}" echo "ilk arguman: ${1-yok}" echo "arguman sayisi: $#"
kutuk: erisim.log ilk arguman: yok arguman sayisi: 0
Değişkenler ve Tırnak Kuralları dersinde tanıtılan ${v-yedek} ve ${v:-yedek}
gösterimleri burada zorunluluğa dönüşür: verilmemiş bir konumsal parametre okunacaksa
öntanımlı değer yazılmalıdır. Bu, betiğin arayüzünü belgeleyen bir yan etki de üretir.
Boru Hattı Kodu
set -o pipefail, boru hattının kodunu sıfırdan farklı kod döndüren en sağdaki komutun
koduna eşitler. Boru Hattı dersinde tanıtılmıştı; katı kipin ayrılmaz parçasıdır.
#!/usr/bin/env bash set -eo pipefail grep '999' erisim.log | wc -l echo "BU SATIR YAZILMAZ"
0
echo $?
1
pipefail olmadan bu betik 0 yazıp başarıyla biterdi: wc sorunsuz çalıştı ve hattın
kodu onunkiydi.
pipefail ve set -e ile birlikte, SIGPIPE ile kesilen hatların da başarısız
sayılacağı unutulmamalıdır. komut | head -5 biçimindeki hatlar bilinçli olarak
bastırılmalıdır.
Alan Ayırıcısını Daraltmak
IFS=$'\n\t' ataması, kelime bölmeden boşluğu çıkarır: bölme yalnızca satır sonu ve
sekmede yapılır.
IFS=$'\n\t' d="a b:c" printf '<%s>\n' $d
<a b:c>
Tırnaksız genişletme bile bölünmedi. Bu, boşluk içeren dosya adlarının yol açtığı hata sınıfına karşı ek bir savunmadır.
Uyarı gerekiyor: bu ayar geneldir ve boşluğa göre bölmeye dayanan her kodu etkiler. Bir değişkeni sözcüklerine ayırmak isteyen bir döngü, ayardan sonra tek tur döner. Katı kipin diğer üç seçeneği koşulsuz önerilirken bu seçenek, betiğin ne yaptığına bakılarak kararlaştırılmalıdır.
Aritmetik Tuzağı
Aritmetik ve Komut Yerine Koyma dersinde (( )) komutunun çıkış kodunun değerin tersi
olduğu gösterilmişti. Katı kip altında bu, betiği durduran bir hataya dönüşür:
#!/usr/bin/env bash set -e sayac=0 (( sayac++ )) echo "BU SATIR YAZILMAZ (sayac=$sayac)"
echo $?
1
sayac++ son ek biçimi eski değeri — yani sıfırı — döndürdü ve (( )) bunu
başarısızlık saydı. Güvenli yazım aritmetik genişletmedir:
#!/usr/bin/env bash set -e sayac=0 sayac=$(( sayac + 1 )) echo "sayac=$sayac"
sayac=1
Bu tuzak, katı kipin neden dikkatle uygulandığını gösterir: seçenekler betiğin anlamını değiştirmez, ama hangi durumların “hata” sayılacağını değiştirir ve bazı deyimler bu yeni tanımla uyumsuzdur.
Beklenen Başarısızlıkları Bastırmak
Bazı komutların sıfırdan farklı kod döndürmesi normaldir; süzgeç aracının “eşleşme yok” bildirimi bunun tipik örneğidir. Katı kip altında bu durumlar açıkça bastırılır.
#!/usr/bin/env bash set -euo pipefail adet=$(grep -c 'YOKBOYLE' erisim.log || true) echo "eslesme sayisi: $adet" if grep -q 'YOKBOYLE' erisim.log; then echo "var"; else echo "yok"; fi
eslesme sayisi: 0 yok
İki yöntem kullanıldı. || true, kodu koşulsuz sıfırlar; sayının kendisi anlamlıysa
uygundur. if içinde çağırmak ise başarısızlığı zaten koşul olarak yorumlar; varlık
sorusunda doğru biçim budur.
|| true ölçülü kullanılmalıdır. Her satıra eklendiğinde katı kip anlamını yitirir ve
betik, hataları yutan eski hâline döner. Kural: bastırma, o komutun başarısızlığının
neden beklenen olduğunu bilerek yapılır ve gerekiyorsa bir yorumla belgelenir.
Hata Kancası
trap ... ERR, erken çıkışı tetikleyen her komut için bir işleyici çalıştırır. Hatanın
nerede oluştuğunu bildirmek, katı kipin ürettiği sessiz çıkışları izlenebilir kılar.
set -E seçeneği bu kancanın fonksiyonlar ve alt kabuklar içinde de geçerli olmasını
sağlar; onsuz kanca yalnızca üst düzeyde çalışır.
#!/usr/bin/env bash set -Eeuo pipefail IFS=$'\n\t' hata_yakala() { local kod=$? satir=$1 printf 'rapor.sh: %d. satirda hata, cikis kodu %d\n' "$satir" "$kod" >&2 exit "$kod" } trap 'hata_yakala "$LINENO"' ERR echo "1: baslangic" grep -q 'YOKBOYLE' erisim.log echo "2: BU SATIR YAZILMAZ"
1: baslangic rapor.sh: 13. satirda hata, cikis kodu 1
Kanca gövdesindeki ilk satır local kod=$? biçiminde yazılmıştır; $? başka bir komut
çalıştırılmadan okunmalıdır, yoksa değeri değişir. $LINENO, kancanın kurulduğu yerde
değil tetiklendiği yerde genişlemesi için tek tırnak içinde bırakılmıştır.
trap komutunun kendisi ve sinyal işleme, sonraki dersin konusudur.
Katı Kip Başlığı
Bu dersin sonucu, betiklerin başına konan sabit bir başlıktır:
#!/usr/bin/env bash set -Eeuo pipefail
Dört seçenek dört ayrı hata sınıfını kapatır: başarısız komut, tanımsız değişken, boru
hattında kaybolan kod ve fonksiyon içinde kaybolan hata kancası. Beşincisi — IFS
daraltması — betiğe göre kararlaştırılır.
Başlık bir güvence değil, bir taban çizgisidir. set -e istisnaları göz önünde
tutulduğunda, kritik komutların kodları hâlâ elle sınanmalıdır. Katı kip, gözden kaçanları
yakalar; gözden kaçmaması gerekenlerin yerini tutmaz.
Özet
set -esıfırdan farklı kod döndüren komuttan sonra kabuğu sonlandırır; koşul bağlamlarında, zincir işleçlerinin solunda ve koşulda çağrılan fonksiyonların gövdesinde askıya alınır.set -utanımsız değişken genişletmesini hata sayar ve öntanımlı değer gösterimlerini zorunlu kılar.set -o pipefailboru hattının kodunu ilk başarısız halkanın koduna bağlar.(( sayac++ ))sıfır değerinde başarısızlık bildirir; katı kip altındasayac=$(( sayac + 1 ))yazılır.- Beklenen başarısızlıklar
|| trueya da koşul bağlamıyla bilinçli olarak bastırılır. set -Eile birliktetrap ... ERR, hatanın satır numarasını bildiren bir kanca kurar.
Sonraki Adım
Katı kip betiği hata anında durduruyor — ama durduğu yerde ne bırakıyor? Yarım yazılmış bir çıktı dosyası, temizlenmemiş geçici dosyalar, başka bir sürecin beklediği bir kilit. Sonraki ders sinyalleri ve çıkışta çalışan temizlik kancalarını ele alır; geçici dosyanın güvenli biçimde yaratılması ve her çıkış yolunda silinmesi de orada kurulacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.