Ders 08 / 24
Özel Değişkenler ve Argümanlar
Konumsal parametreler, argüman listesinin iki gösterimi, listeyi tüketen döngü ve seçenek ayrıştırma.
İçindekiler
Kütük adı artık bir değişkenden geliyor, ama betiği çağıran için doğal yol bu değildir.
KUTUK=erisim.log ./rapor.sh yazmak yerine ./rapor.sh erisim.log yazmak beklenir.
Komut satırından gelen değerler, kabukta ayrı bir mekanizmayla — konumsal parametreler
(positional parameters) ile — karşılanır.
Programlama Temelleri kursunda fonksiyon parametreleri adlarıyla tanımlanıyordu. Kabukta adlandırma yoktur: parametreler numaralanır ve numaralarıyla okunur. Bu ders o numaraları, listeyi bir bütün olarak ele almanın iki yolunu ve seçenek ayrıştırmayı kurar.
Konumsal Parametreler
$1, $2, … betikçe alınan argümanları sırayla verir. $0 betiğin çağrıldığı adı,
$# argüman sayısını tutar.
#!/usr/bin/env bash echo "betik adi : $0" echo "arguman sayisi: $#" echo "ilk : $1" echo "ikinci : $2" echo "onuncu : ${10}"
./arg.sh a b c d e f g h i j
betik adi : ./arg.sh arguman sayisi: 10 ilk : a ikinci : b onuncu : j
Dokuzdan büyük numaralar süslü ayraç ister. $10 yazılsaydı kabuk bunu $1 ve 0 diye
okur, ilk argümanın ardına sıfır ekleyerek a0 üretirdi. Ayraç kullanımı bu yüzden
zorunludur.
$0, betiğin çalıştırılırken yazıldığı addır; dosyanın gerçek adı olmak zorunda değildir
ve saltık yol içermeyebilir. Kullanım iletilerinde $0 yazmak yaygındır ama betiğin
adını sabit yazmak daha okunaklı bir çıktı verir.
Argüman Listesi: "$@" ve "$*"
Tüm argümanları birlikte aktarmak için iki gösterim vardır ve aralarındaki fark yalnızca tırnak içinde ortaya çıkar.
"$@", her argümanı ayrı bir kelime olarak genişletir."$*", tüm argümanlarıIFS’in ilk karakteriyle birleştirip tek kelime üretir.- Tırnaksız
$@ve$*, ikisi de kelime bölmeye uğrar ve ayrım kaybolur.
#!/usr/bin/env bash say() { printf 'sayi=%d\n' "$#"; printf ' <%s>\n' "$@"; } echo '--- "$@" ---'; say "$@" echo '--- "$*" ---'; say "$*" echo '--- $@ ---'; say $@
./liste.sh "erisim kutugu.log" 404
--- "$@" --- sayi=2 <erisim kutugu.log> <404> --- "$*" --- sayi=1 <erisim kutugu.log 404> --- $@ --- sayi=3 <erisim> <kutugu.log> <404>
Üç sonuç üç farklı anlam taşır. İlki, çağıranın verdiği sınırları koruyarak listeyi aktarır. İkincisi listeyi tek metne çevirir — ileti yazdırmak dışında bir işe yaramaz. Üçüncüsü, boşluk içeren argümanı ikiye böler ve çağıranın niyetini bozar.
Kural: argümanları başka bir komuta aktarırken her zaman "$@" kullanın. Bu, önceki
dersteki tırnaklama kuralının konumsal parametrelere uzanmasıdır.
Listeyi Tüketmek
shift komutu konumsal parametreleri bir sola kaydırır: $2 yeni $1 olur, $# bir
azalır. Argümanları sırayla işleyen döngülerin temelidir.
#!/usr/bin/env bash while [ "$#" -gt 0 ]; do echo "islenen: $1 (kalan: $#)" shift done
./shift.sh bir iki uc
islenen: bir (kalan: 3) islenen: iki (kalan: 2) islenen: uc (kalan: 1)
shift N biçimi bir defada N parametre atar. Kalan parametre sayısından fazlasını
atmaya çalışmak sıfırdan farklı kod döndürür ve listeyi değiştirmez.
Betiğe İlişkin Özel Değişkenler
Kabuk, çalışan betik hakkında birkaç değeri özel adlarda tutar.
| Ad | İçerik |
|---|---|
$? |
son komutun çıkış kodu |
$$ |
çalışan kabuğun süreç numarası |
$! |
arka planda başlatılan son sürecin numarası |
$- |
etkin kabuk seçenekleri |
$0 |
betiğin çağrıldığı ad |
$# |
konumsal parametre sayısı |
$$ geçici dosya adı üretmekte sık kullanılır; ancak süreç numaraları yeniden
kullanılabildiği için tek başına güvenli değildir. Tuzaklar ve Temizlik dersinde mktemp
ile doğru yol gösterilecek.
$! arka plan süreçlerini beklemek ve durdurmak için gerekir; Çıkış Kodları dersinde
sinyal kodları bu değişkenle üretilmişti.
Seçenek Ayrıştırma
Argümanları elle ayrıştırmak — birinci argüman seçenekse, ikinci onun değeriyse … —
kısa sürede okunmaz hâle gelir. getopts yerleşik komutu kısa seçenekleri sözleşmeye
uygun biçimde ayrıştırır.
getopts iki argüman alır: tanınan seçeneklerin dizisi ve bulunan seçeneğin yazılacağı
değişken adı. Dizideki bir harfin ardından : gelirse o seçenek değer bekler; değer
OPTARG değişkenine konur. Dizinin başındaki :, hata iletilerini getopts’un değil
betiğin üreteceğini bildirir.
#!/usr/bin/env bash adet=5 ayrinti=0 while getopts ':n:va' secenek; do case "$secenek" in n) adet="$OPTARG" ;; v) ayrinti=1 ;; a) echo "kullanim: sec.sh [-n SAYI] [-v] KUTUK"; exit 0 ;; :) echo "hata: -$OPTARG deger bekliyor" >&2; exit 2 ;; \?) echo "hata: bilinmeyen secenek -$OPTARG" >&2; exit 2 ;; esac done shift $((OPTIND - 1)) echo "adet=$adet ayrinti=$ayrinti kalan=$# ilk=[${1-yok}]"
Dört çağrı, dört davranışı gösterir:
./sec.sh -n 3 -v erisim.log ./sec.sh erisim.log ./sec.sh -n ./sec.sh -z
adet=3 ayrinti=1 kalan=1 ilk=[erisim.log] adet=5 ayrinti=0 kalan=1 ilk=[erisim.log] hata: -n deger bekliyor hata: bilinmeyen secenek -z
Son iki çağrı 2 koduyla sonlandı. Kullanım hatasını başka bir hata sınıfından ayrı bir
kodla bildirmek, betiği zincirde kullanılabilir kılar.
OPTIND, getopts’un işlediği son argümanın sırasını tutar. Döngüden sonraki
shift $((OPTIND - 1)) satırı seçenekleri listeden atar; geriye yalnızca seçenek olmayan
argümanlar kalır. Bu satır unutulursa $1 hâlâ ilk seçeneği gösterir.
getopts yalnızca tek harfli seçenekleri tanır; --ayrinti gibi uzun seçenekler için
destek yoktur. Uzun seçenek gerekiyorsa while–case ile elle ayrıştırma yazılır. Ayrıca
case dallarındaki \? yazımındaki ters bölü gereklidir: ? case kalıplarında tek
karakter eşleyen özel bir simgedir.
Argüman Sonu İşareti
Tire ile başlayan bir değer, seçenek sanılabilir. Örneğin -eski.log adlı bir dosya,
çoğu komut tarafından seçenek olarak yorumlanır. Sözleşme, argüman listesinde --
görüldüğünde ondan sonrasının seçenek olmadığını kabul etmektir:
grep -- '-404-' erisim.log
Kendi betiklerinizde de getopts bu işareti tanır ve orada durur. Değişkenden gelen
dosya adlarını başka bir komuta aktarırken -- yazmak, kullanıcı girdisiyle seçenek
karışmasını önler.
Betiğe Uygulama
rapor.sh artık bir arayüz kazanır: kaç satır listeleneceği -n ile, kütük adı ilk
konumsal parametreyle verilir.
#!/usr/bin/env bash # rapor.sh — erisim kutugunden ozet rapor uretir. # Kullanim: rapor.sh [-n SAYI] [KUTUK] adet=5 while getopts ':n:' secenek; do case "$secenek" in n) adet="$OPTARG" ;; :) echo "hata: -$OPTARG deger bekliyor" >&2; exit 2 ;; \?) echo "hata: bilinmeyen secenek -$OPTARG" >&2; exit 2 ;; esac done shift $((OPTIND - 1)) kutuk="${1:-erisim.log}" echo "== Kutuk: $kutuk (ilk $adet yol) ==" cut -d' ' -f7 "$kutuk" | sort | uniq -c | sort -rn | head -"$adet"
./rapor.sh -n 3
== Kutuk: erisim.log (ilk 3 yol) == 6 /api/veri 4 /yok.html 4 /index.html
Betik hâlâ eksik: verilen kütük yoksa cut hata verir ve rapor başlığı boşuna basılmış
olur. Bu eksik sonraki dersin konusudur.
Özet
- Konumsal parametreler
$1’den başlar; dokuzdan büyük numaralar süslü ayraç ister.$#sayıyı,$0çağrılan adı verir. "$@"argümanları ayrı kelimeler olarak,"$*"tek kelime olarak genişletir; tırnaksız yazımda ikisi de kelime bölmeye uğrar. Aktarımda"$@"kullanılır.shiftlisteyi bir sola kaydırır ve argümanları sırayla tüketen döngüyü mümkün kılar.getoptskısa seçenekleri ayrıştırır;OPTARGdeğeri,OPTINDişlenen sırayı tutar ve döngüden sonrashift $((OPTIND - 1))gerekir.--işareti, ondan sonrasının seçenek olmadığını bildirir ve tire ile başlayan değerleri korur.
Sonraki Adım
Betik, kendisine verilen kütüğün var olduğunu ve okunabildiğini varsayıyor. Bu varsayımı
sınamak için bir koşul gerekir; kabukta koşul, bir komutun çıkış kodudur. Sonraki ders
dosya, dizgi ve sayı testlerini, [ ] ile [[ ]] arasındaki farkı ve bu farkın neden
sözdizim tercihi değil doğruluk meselesi olduğunu ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.