Ders 09 / 24
Koşullar ve Testler
Koşulun bir çıkış kodu olması, dosya/dizgi/sayı testleri, tek ve çift ayraç arasındaki ayrıştırma farkı, kalıp eşleme ve çoklu seçim.
İçindekiler
Betik, kendisine verilen kütüğün var olduğunu ve okunabildiğini varsayıyor. Varsayımı sınamak bir koşul gerektirir. Programlama Temelleri kursunda koşul, mantıksal bir ifadeydi ve doğru ya da yanlış değerine indirgenirdi.
Kabukta böyle bir tip yoktur. Koşul, çalıştırılan bir komuttur; sonucu çıkış kodudur.
if yapısı bir ifadeyi değerlendirmez, bir komut çalıştırır ve kodu 0 ise gövdeyi
yürütür. Bu tek fark, kabuk koşullarının tüm sözdizim tuhaflıklarını açıklar.
if Bir Komut Alır
if komut; then ... elif baska_komut; then ... else ... fi
Herhangi bir komut koşul olabilir:
if grep -q '404' erisim.log; then echo "kutukte 404 var" fi
Koşullar için kullanılan [ ... ] yazımı bir sözdizim öğesi değil, test adlı komutun
ikinci adıdır. Bu yüzden [ ile ilk argüman arasında boşluk zorunludur ve kapanış ]
bu komutun son argümanıdır. [-f dosya] yazımı [-f adında bir komut arar ve
bulunamaz.
Dosya Testleri
test, dosya sistemine ilişkin bir işleçler ailesi tanır.
| İşleç | Doğru olduğu durum |
|---|---|
-e |
yol var (türü ne olursa olsun) |
-f |
düz dosya |
-d |
dizin |
-r, -w, -x |
okuma / yazma / çalıştırma izni var |
-s |
dosya var ve boyutu sıfırdan büyük |
-L |
sembolik bağ |
a -nt b |
a, b’den daha yeni değiştirilmiş |
[ -f erisim.log ]; echo "duz dosya -> $?" [ -d erisim.log ]; echo "dizin -> $?" [ -x erisim.log ]; echo "calistirma -> $?"
duz dosya -> 0 dizin -> 1 calistirma -> 1
İzin testleri, dosyanın izin bitlerini değil çağıran sürecin o dosyada o işlemi yapıp yapamayacağını sınar; süper kullanıcı için sonuç farklı çıkabilir. Linux’a Giriş kursunda kurulan izin modeli burada davranışa dönüşür.
-e ile -f ayrımı ihmal edilmemelidir: bir dizin de -e sınamasını geçer, ama cut
ile okunamaz.
Dizgi ve Sayı Testleri
Dizgi testleri: -z boş mu, -n boş değil mi, = eşit mi, != farklı mı.
Sayı testleri ayrı işleçler kullanır: -eq, -ne, -lt, -le, -gt, -ge.
İki ailenin ayrı olması gereklidir, çünkü kabukta her değer bir karakter dizisidir ve “eşitlik” iki farklı anlama gelir:
[ "007" = "7" ]; echo "dizgi esitligi -> $?" [ "007" -eq "7" ]; echo "sayi esitligi -> $?"
dizgi esitligi -> 1 sayi esitligi -> 0
007 ile 7 farklı dizgilerdir ama aynı sayıdır. Hangi anlamın istendiğine yazan karar
verir; işleç seçimi bu kararın bildirimidir.
Sayı işleçleri yalnızca tam sayılarla çalışır. Ondalıklı değer verilirse test hata
bildirir. Ondalıklı karşılaştırma gerekiyorsa bir hesaplama aracına başvurulur; bu,
Aritmetik ve Komut Yerine Koyma dersinde ele alınacak.
Tek Ayracın Ayrıştırma Sorunu
[ sıradan bir komut olduğu için argümanları önce kabuk tarafından genişletilir ve
kelimelere bölünür. Bölme sonucu, test’in beklediği argüman sayısını değiştirebilir.
bos="" [ $bos = "x" ]
bash: [: =: unary operator expected
Genişletme sonrası [ komutuna yalnızca =, x, ] argümanları ulaştı; test bunu
tek işlenenli bir ifade sandı. Aynı sorun boşluk içeren değerde ters yönde çıkar:
d="iki kelime" [ $d = "iki kelime" ]
bash: [: too many arguments
Her iki hata da tırnaklamayla giderilir:
[ "$bos" = "x" ]; echo "kod=$?"
kod=1
Eski betiklerde [ "x$a" = "xb" ] biçiminde bir kalıp görülür. Amacı, değişkenin
değerinin bir işleçle karışmasını önlemektir; tırnaklama yeterli olduğu için bu kalıp
artık gereksizdir, ama karşılaşıldığında ne yaptığı bilinmelidir.
Çift Ayraç
Bash ve ksh, [[ ... ]] adında ayrı bir sözdizim öğesi tanır. Bu bir komut değildir;
kabuk onu ayrıştırma aşamasında tanır ve içindeki genişletmelere kelime bölme ile yol
adı genişletmesi uygulamaz.
bos=""; d="iki kelime" [[ $bos = "x" ]]; echo "bos -> $?" [[ $d = "iki kelime" ]]; echo "bosluklu -> $?"
bos -> 1 bosluklu -> 0
Tırnaksız yazımlar hata vermedi. Bu, [[ ]] içinde tırnak gerekmediği anlamına gelir —
ama tırnak yazmak da zarar vermez ve alışkanlığı bozmamak için yeğlenebilir.
Çift ayracın üç ek yeteneği vardır.
Kalıp eşleme. = veya == işlecinin sağ yanı tırnaksızsa yol adı kalıbı olarak
yorumlanır:
yol="/api/veri" [[ $yol == /api/* ]] && echo "api altinda" [[ $yol == "/api/*" ]] || echo "tirnaklanmis kalip harfi harfine"
api altinda tirnaklanmis kalip harfi harfine
Sağ yanın tırnaklanması kalıbı sıradan dizgiye çevirir. Bu, kalıp eşlemesinin istenmediği durumlarda gerekli olan denetimdir.
Düzenli ifade eşleme. =~ işleci sağ yanı genişletilmiş düzenli ifade sayar:
kod="404" [[ $kod =~ ^[45][0-9][0-9]$ ]] && echo "hata sinifi kodu"
hata sinifi kodu
Düzenli ifade yazımı Metin İşleme konusunda ayrıntılı ele alınacak. Burada önemli olan, kalıbın tırnaksız yazılmasıdır: tırnaklanan bir sağ yan harfi harfine eşleşme arar.
Mantıksal işleçler. && ve ||, ayraç içinde koşulları birleştirir:
[[ -f erisim.log && -r erisim.log ]] && echo "okunabilir dosya"
okunabilir dosya
[ ] içinde aynı iş için -a ve -o işleçleri bulunur, ancak bunlar ayrıştırma
belirsizliği ürettikleri için önerilmez. Taşınabilir yazımda iki ayrı test && ile
zincirlenir:
[ -f erisim.log ] && [ -r erisim.log ] && echo "okunabilir dosya"
[[ ]] bash eklentisidir; POSIX kabuk dilinde yoktur. #!/bin/sh bildiren bir
betikte kullanılamaz. Karar kuralı: bash bildiriliyorsa [[ ]] yeğlenir — tırnaklama
hatalarına karşı bağışıktır; POSIX gerekiyorsa [ ] ve titiz tırnaklama kullanılır.
Çoklu Seçim
Aynı değeri birçok olasılığa karşı sınayan if–elif zincirleri yerine case yazılır.
Kalıplar yol adı kalıbı sözdizimini kullanır.
for k in 200 301 404 500 xyz; do case "$k" in 2??) sinif="basarili" ;; 3??) sinif="yonlendirme" ;; 4??) sinif="istemci hatasi" ;; 5??) sinif="sunucu hatasi" ;; *) sinif="tanimsiz" ;; esac printf '%-4s -> %s\n' "$k" "$sinif" done
200 -> basarili 301 -> yonlendirme 404 -> istemci hatasi 500 -> sunucu hatasi xyz -> tanimsiz
case, ilk eşleşen dalı çalıştırır ve durur; dallar arasında düşme yoktur. Bir kalıba
birden çok seçenek | ile eklenir: 200|201|204). Son dal olarak yazılan *), hiçbir
kalıba uymayan değerleri yakalar ve her case yapısında bulunmalıdır — eksikse tanınmayan
değer sessizce yok sayılır.
case POSIX’tir ve [[ ]] gerektirmeden kalıp eşleme sağlar; taşınabilir betiklerde
kalıp sınamasının doğru aracıdır.
Betiğe Uygulama
rapor.sh girdilerini sınayacak biçimde genişletilir. Hata sınıflarına ayrı kodlar
verilmesi, önceki dersteki sözleşmenin sürdürülmesidir.
kutuk="${1:-erisim.log}" if ! [[ "$adet" =~ ^[0-9]+$ ]] || [ "$adet" -lt 1 ]; then echo "hata: -n icin pozitif tam sayi bekleniyor: $adet" >&2 exit 2 fi if [ ! -e "$kutuk" ]; then echo "hata: kutuk yok: $kutuk" >&2 exit 3 elif [ ! -f "$kutuk" ]; then echo "hata: duz dosya degil: $kutuk" >&2 exit 3 elif [ ! -r "$kutuk" ]; then echo "hata: okuma izni yok: $kutuk" >&2 exit 3 elif [ ! -s "$kutuk" ]; then echo "uyari: kutuk bos: $kutuk" >&2 fi
Sayı sınamasında [ "$adet" -lt 1 ] testinden önce düzenli ifade sınaması yapılmasının
nedeni sıradır: adet sayı değilse -lt hata verirdi. || kısa devre yaptığı için ikinci
sınamaya yalnızca birincisi geçtiğinde ulaşılır.
Dört çağrı dört yolu izler:
./rapor.sh yok.log; echo "kod=$?" ./rapor.sh -n abc; echo "kod=$?" ./rapor.sh /etc; echo "kod=$?"
hata: kutuk yok: yok.log kod=3 hata: -n icin pozitif tam sayi bekleniyor: abc kod=2 hata: duz dosya degil: /etc kod=3
Özet
- Kabukta koşul bir komuttur;
ifçıkış koduna bakar.[ ],testkomutunun ikinci adıdır ve çevresindeki boşluklar zorunludur. - Dizgi eşitliği
=, sayı eşitliği-eqile sınanır;007ile7dizgi olarak farklı, sayı olarak aynıdır. [ ]içindeki genişletmeler kelime bölmeye uğradığı için tırnaklama zorunludur; boş veya boşluklu değer aksi hâlde ayrıştırma hatası üretir.[[ ]]ayrıştırma düzeyinde tanınır, bölme uygulamaz, kalıp ve düzenli ifade eşlemesi ile mantıksal işleçler sunar; bash eklentisidir.caseilk eşleşen dalı çalıştırır, düşme yoktur ve*)dalı her zaman yazılmalıdır.
Sonraki Adım
Rapor şu an tek bir listeyi üretiyor. Durum kodu sınıflarının her biri için ayrı sayım istendiğinde aynı boru hattını elle çoğaltmak gerekir. Sonraki ders yinelemeyi ele alır: liste üzerinde dönen döngüler, sayaçlı döngüler ve bir dosyayı satır satır okumanın — kabukta hiç de apaçık olmayan — doğru biçimi.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.