İçeriğe geç
academia.sh

Ders 06 / 24

Betik Anatomisi

Yorumlayıcı bildirimi, çalıştırma izni, betiği çalıştırmanın üç yolu ve alt süreçle kaynak okuma arasındaki fark.

İçindekiler

Önceki konu, komutları akışlarla ve çıkış kodlarıyla birbirine bağlamayı kurdu. Ortaya çıkan hatlar tek satırlıktı: yazıldıkları anda çalıştılar ve kayboldular. Aynı hattı her gün çalıştırmak, üzerine seçenek eklemek ve başkasına devretmek gerektiğinde tek satır yetmez.

Betik (script), kabuğun okuyup sırayla yürüttüğü komutları tutan sıradan bir metin dosyasıdır. Bu ders dosyanın ne olduğunu, çekirdeğin onu nasıl çalıştırdığını ve üç farklı çalıştırma yolunun süreç açısından ne anlama geldiğini ele alır.

İlk Betik

Önceki dersin son hattı bir dosyaya alınır:

#!/usr/bin/env bash
# rapor.sh — erisim kutugunden ozet rapor uretir.

echo "== En cok istenen yollar =="
cut -d' ' -f7 erisim.log | sort | uniq -c | sort -rn | head -5

Bu dosya rapor.sh adıyla kaydedilir. Kurs boyunca her konu bu betiği bir adım ilerletecek; sonunda argüman alan, hataya dayanıklı ve zamanlanmış olarak çalışan bir araç hâline gelecek.

# ile başlayan satırlar yorumdur; kabuk onları yok sayar. Yorum işareti satır başında olmak zorunda değildir ama kelime ortasında yorum başlatmaz:

echo abc#def
echo abc #def
abc#def
abc

Yorumun başlaması için # işaretinin bir kelimenin başında bulunması gerekir. Bu, dosya adlarında ve URL’lerde # geçtiğinde işe yarayan bir kuraldır.

Çalıştırma İzni

Betik dosyası yaratıldığında çalıştırma izni taşımaz. Doğrudan çağrılırsa:

./rapor.sh
bash: ./rapor.sh: Permission denied
echo $?
126

Kod 126, “dosya bulundu ama çalıştırılamadı” anlamına gelir; önceki derste ayrılmış kodlar arasında geçmişti. İzin verilir:

chmod +x rapor.sh
./rapor.sh
== En cok istenen yollar ==
   6 /api/veri
   4 /yok.html
   4 /index.html
   3 /urun/45
   3 /urun/12

Betiğin adının önündeki ./ bırakılırsa sonuç değişir:

rapor.sh
bash: rapor.sh: command not found
echo $?
127

Linux’a Giriş kursunun komut yolu dersinde kurulan kural burada işler: eğik çizgi içermeyen bir ad, yalnızca PATH içindeki dizinlerde aranır ve bulunulan dizin bu listede yer almaz. ./rapor.sh yazımı adı bir yol hâline getirir ve arama yapılmaz.

Bulunulan dizini PATH listesine eklemek yaygın bir öneri değildir: o dizine ls adında bir dosya bırakan herkes, orada çalıştırdığınız her komutu ele geçirebilir.

Yorumlayıcı Bildirimi

Betiğin ilk satırındaki #! dizisi bir yorum gibi görünür ama işlevi kabuğun değil çekirdeğin ilgi alanındadır. Dosyanın ilk iki baytı #! ise, çekirdek onu doğrudan çalıştırmaya kalkmaz; satırın kalanını bir program yolu olarak okur, o programı başlatır ve betik dosyasının yolunu ona argüman olarak verir.

Bu düzeneğe yorumlayıcı bildirimi (shebang) denir. Üç ayrıntısı vardır.

Yalnızca ilk satırda geçerlidir. İkinci satırdaki #! sıradan yorumdur. İlk satırın ilk iki baytı #! değilse bildirim yoktur.

Yol saltıktır, arama yapılmaz. Çekirdek PATH bakmaz. #!/bin/bash yazan bir betik, bash’in /bin/bash yolunda bulunmadığı bir sistemde çalışmaz.

Bildirim yoksa davranış çağırana kalır. Çekirdek dosyayı çalıştıramaz ve hata döndürür; bunun üzerine çağıran kabuk çoğu durumda dosyayı kendi alt kabuğuna okutur. Sonuç, betiği çalıştıran kabuğa bağlıdır — yani taşınabilir değildir.

printf 'echo "shebangsiz calisti: $0"\n' > yalin.sh
chmod +x yalin.sh
./yalin.sh
shebangsiz calisti: ./yalin.sh

Çalıştı, ama hangi kabukla çalıştığı garanti değildir. Her betiğe yorumlayıcı bildirimi yazmak zorunlu bir alışkanlıktır.

Hangi Yorumlayıcı

İki yaygın yazım vardır ve seçim betiğin ne kullandığına bağlıdır.

#!/bin/sh, POSIX kabuk dilini bildirir. Bu yolun ucundaki programın hangi kabuk olduğu sisteme göre değişir; verilen tek güvence, POSIX kabuk dilini yorumlayacağıdır. Dizi, [[ ]], <<<, ${var,,} gibi bash eklentileri bu bildirimle kullanılamaz — bazı sistemlerde çalışıyor görünmeleri yanıltıcıdır, çünkü orada /bin/sh bash’in POSIX kipidir.

#!/usr/bin/env bash, env komutunu çağırarak bash’i PATH içinde arar. Bash’in sistemden sisteme farklı yerlerde kurulu olması bu yazımla soğurulur. Bedeli, PATH üzerinden dolaylı bir arama yapılmasıdır; sabit yol gerektiren sıkı ortamlarda #!/bin/bash yeğlenir.

Karar kuralı: betikte bash’e özgü tek bir özellik kullanıyorsanız bash bildirin. POSIX bildirip bash özelliği kullanmak, betiğin başka bir sistemde sessizce bozulmasının en sık nedenidir. Bu kursta bash’e özgü her özellik metinde açıkça belirtilecek.

Bash sürümleri arasında da fark vardır. Bir sistemde /bin/bash eski bir ana sürüm olabilir; ilişkisel diziler gibi özellikler orada yoktur. Diziler ve İlişkisel Diziler dersinde bu farkın ölçülebilir bir örneği verilecek.

Çalıştırmanın Üç Yolu

Aynı betik üç farklı biçimde yürütülebilir ve üçü aynı şey değildir.

Doğrudan çalıştırma (./rapor.sh) çalıştırma izni ve yorumlayıcı bildirimi ister. Yeni bir süreç yaratılır.

Yorumlayıcıya argüman olarak verme (bash rapor.sh) ne izin ne bildirim ister; bildirim varsa da yok sayılır, çünkü dosya çalıştırılmaz, okunur. Yine yeni bir süreç yaratılır.

Kaynak okuma (. rapor.sh veya source rapor.sh) yeni süreç yaratmaz. Komutlar o anki kabuğun içinde yürütülür.

Üçüncüsünün farkı gözlemlenebilir. ayar.sh yalnızca bir değişken atasın:

KUTUK=erisim.log
bash ayar.sh
echo "alt surec sonrasi: [${KUTUK-tanimsiz}]"
. ./ayar.sh
echo "source sonrasi: [${KUTUK-tanimsiz}]"
alt surec sonrasi: [tanimsiz]
source sonrasi: [erisim.log]

Alt süreçte yapılan atama, süreçle birlikte kayboldu. Boru hattı dersindeki alt kabuk davranışının aynısıdır: süreçler arasında değişken geçmez. Kaynak okuma bu yüzden yapılandırma dosyaları ve fonksiyon kitaplıkları için kullanılır; iş yapan betikler için uygun değildir, çünkü betiğin exit çağrısı çağıran kabuğu kapatır.

. yazımı POSIX’tir, source bash eklentisidir; ikisi aynı işi yapar. POSIX yazımında dosya adı eğik çizgi içermiyorsa PATH içinde aranır — . ./ayar.sh yazımındaki ./ bu yüzden gereklidir.

Betiğin Çıkış Kodu

Bir betik, son çalıştırdığı komutun kodunu döndürür. Aşağıdaki betiğin son satırı eşleşme bulamayan bir grep ise:

#!/usr/bin/env bash
grep -q '999' erisim.log
./sonkod.sh; echo "kod=$?"
kod=1

Betik başarılı çalıştı ama başarısızlık bildirdi. Bu davranış istenmiyorsa kod açıkça yazılır: exit 0. Çıkış kodunu bilinçli belirlemek, betiği bir zincirde ya da zamanlanmış görevde kullanılabilir kılan şeydir.

Çalıştırmadan Sözdizim Denetimi

bash -n seçeneği betiği okur, ayrıştırır ama çalıştırmaz. Yarım kalmış bir yapı varsa bildirir:

bash -n bozuk.sh
bozuk.sh: line 4: syntax error: unexpected end of file from `if' command on line 2

Bu denetim yalnızca sözdizimini görür; var olmayan komutları, yanlış seçenekleri veya mantık hatalarını yakalamaz. Yine de yıkıcı işlem içeren bir betiği ilk kez çalıştırmadan önce yapılacak en ucuz sınamadır. Hata ayıklama araçlarının tamamı Betik Hata Ayıklama dersinde ele alınacak.

Özet

  • Betik, kabuğun sırayla yürüttüğü komutları tutan metin dosyasıdır; # ile başlayan kelimeler yorum açar.
  • Doğrudan çalıştırma çalıştırma izni ister; izin yoksa kod 126, ad PATH içinde bulunamazsa 127 döner.
  • İlk iki baytı #! olan dosyada çekirdek, satırın kalanındaki saltık yolu yorumlayıcı olarak başlatır; arama yapmaz ve yalnızca ilk satıra bakar.
  • #!/bin/sh yalnızca POSIX kabuk dilini güvence altına alır; bash eklentisi kullanan betik bash bildirmelidir.
  • bash betik yeni süreç yaratır, . betik yaratmaz; ikincisinde atamalar çağıran kabukta kalır.

Sonraki Adım

Betiğin gövdesindeki kütük adı şimdilik sabit yazılı. Onu bir değişkene almak ilk bakışta yalnızca düzen meselesi görünür; oysa kabukta değişken genişletmenin sonucu tırnak kullanımına göre değişir ve tırnaksız bir genişletme, boşluk içeren dosya adlarında betiği sessizce yanlış çalıştırır. Sonraki ders genişletme, kelime bölme ve alıntılama kurallarını ele alır.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat