Bash kabuğunda betik yazmanın incelikleri — 4

Gökhan Şengün
3 min readAug 6, 2018

--

Bu flood’da yine Linux işletim sisteminde Bash kabuğunda (shell) çalıştırmak üzere yazılan betiklerden (script) bahsederek seriyi kapatacağız.

Bash içerisinde Web sunucu, TCP sunucu, vb bir daemon çalıştırmamız gerektiğinde ana betiği meşgul etmemek için ilgili servis arka planda başlatılabilir. Bir programı arka planda başlatmak için komutun sonuna & işareti konur, başlatılan programın PID'si ekranda gösterilir.

Önceki flood’larda Bash'in $? değişkeninde koşturulan son prosesin çıkış değerini verdiğini söylemiştik. Benzer şekilde $! değişkeninde de başlatılan son prosesin PID'si tutulur. Aşağıdaki örnekte daemon olarak çalıştırılan web sunucunun PID'si bu yöntem ile alınmıştır.

Daemon arka planda çalıştırıldıktan sonra betik içerisinde başka işlemler gerçekleştirilerek başlatılan daemon’ın da belirli bir süre sonra kapatılması gerekebilir. Daemon’ın PID'si başlatılırken elde edildiği için daemon'a gerekli sinyal gönderilerek kapanması sağlanabilir.

Başka bir kullanım alanında ise batch işlemler yapan ve uzun süren bir veya daha fazla prosesi arka planda başlatarak PID'lerini kaydederek betik içerisinde bitmelerini bekleyebiliriz. wait komutu ile kabuk tarafından çalıştırılan bütün proseslerin bitmesi beklenebilir.

Aşağıdaki Bash betiğinde birer saniye aralıklarla ekrana dört kere yazı yazacak iki proses arka planda başlatılmış ve ana betik içerisinden wait ile beklenmiştir. Bütün çocuk prosesler bittikten sonra wait programı çıkış yapmış ve akış devam etmiştir.

wait programının arka planda çalıştırılan proseslerin bitmesini bekleyebilmesi için başlatılan proseslerin parent'i olması gerekir. Eğer prosesler nohup, screen ve disown gibi programlarla çalıştırılıp kabuktan koparılırsa wait ile takip edilemezler.

wait programı başlatılan prosesleri toplu bir şekilde beklemeye olanak tanır ancak herhangi bir zamanda topluca başlatılan proseslerin hangilerinin bittiği ile ilgili bilgilendirme yapmaz. Bu ihtiyaca cevap vermek üzere çok güzel bir hile geliştirilmiştir. kill -0 <pid> komutu aracılığıyla prosese 0 numaralı sinyal gönderilir. man sayfasından da bakılabileceği üzere aslında 0 diye bir sinyal yoktur. Burada kill komutu sadece verilen PID ile ilgili hata kontrolü yapar ve proses yoksa 0'dan farklı bir çıkış kodu üretir.

Aşağıdaki örnekte arka planda başlatılan prosesin bitip bitmediği kill -0 <PID> komutu ile birer saniye aralıklarla kontrol edilmiştir.

Zaman zaman Bash'te komutları gruplama ihtiyacı oluşur. Gruplanan komutların ayrı bir kabukta (sub-shell) koşturulması için parantez (...), mevcut kabukta koşturulması için ise süslü parantez {...} içine yazılması gerekir.

Komutların gruplanmasına örnek olarak bir komut hata verdiğinde birden fazla komutun koşturulması gerektiği durum verilebilir. Aşağıdaki örnekte çıkış kodu 1 olan /bin/false programı çalıştıktan sonra koşturulmak üzere bir komut grubu verilmiştir.

Bash, güncel olarak yoğunlukla konteynerların başlatma betiği olarak kullanılmaktadır. Betikler bazı kontrollerden sonra konteynerin çalıştıracağı asıl programı başlatmaktadırlar. Örnek olarak Postgres konteynerinde parola boş geçilmişse Bash ile kullanıcı uyarılmaktadır.

İşte bu noktada konteyner başlatma betiği, asıl programı bir sub-shell'de çalıştırmak yerine exec programı yardımıyla kendi prosesi tarafından çalışır hale getirir ve kendisi ölmüş olur. Bu sayede konteynere gönderilen sinyaller direkt olarak ilgili programa gönderilebilir.

Nadiren ise konteyner başlatma betiğinde exec kullanılmaz ve bash ana programı bir sub-shell'de çalıştırır. Bu durumlarda bash'in konteynere gelen sinyalleri yakalayarak ana prosese göndermesi gerekmektedir. Aşağıda bu işlemi gerçekleştiren bir betik verilmiştir.

--

--

Gökhan Şengün

Full stack dad of two and just curious about things. Stories are from my twitter floods @gokhansengun. Main blog is www.gokhansengun.com