Bash Komut Dosyalarında Linux Sinyalleri Nasıl Kullanılır
Yayınlanan: 2022-08-09
Linux çekirdeği, tepki vermeleri gereken olaylar hakkında süreçlere sinyaller gönderir. İyi niyetli komut dosyaları, sinyalleri zarif ve sağlam bir şekilde işler ve Ctrl+C'ye bassanız bile arkalarını temizleyebilir. İşte nasıl.
Sinyaller ve Süreçler
Sinyaller, komut dosyaları, programlar ve arka plan programları gibi işlemlere gönderilen kısa, hızlı, tek yönlü mesajlardır. Sürecin olan bir şey hakkında bilgi sahibi olmasını sağlarlar. Kullanıcı Ctrl+C'ye basmış olabilir veya uygulama erişimi olmayan belleğe yazmaya çalışmış olabilir.
Sürecin yazarı, kendisine belirli bir sinyalin gönderilebileceğini öngördüyse, bu sinyali işlemek için programa veya komut dosyasına bir rutin yazabilir. Böyle bir rutine sinyal işleyici denir. Sinyali yakalar veya yakalar ve buna yanıt olarak bazı eylemler gerçekleştirir.
Göreceğimiz gibi, Linux çok sayıda sinyal kullanır, ancak komut dosyası oluşturma açısından, ilgilenebileceğiniz yalnızca küçük bir sinyal alt kümesi vardır. Özellikle, önemsiz olmayan komut dosyalarında, kapatılacak komut dosyası tuzağa düşürülmeli (mümkünse) ve zarif bir kapatma gerçekleştirilmelidir.
Örneğin, geçici dosyalar oluşturan veya güvenlik duvarı bağlantı noktalarını açan komut dosyalarına, geçici dosyaları silme veya bağlantı noktalarını kapatmadan önce kapatma şansı verilebilir. Komut dosyası, sinyali aldığı anda ölürse, bilgisayarınız öngörülemeyen bir durumda kalabilir.
Kendi komut dosyalarınızdaki sinyalleri nasıl ele alabileceğiniz aşağıda açıklanmıştır.
Sinyallerle Tanışın
Bazı Linux komutlarının şifreli adları vardır. Sinyalleri yakalayan komut öyle değil. trap
denir. Ayrıca, Linux'un kullandığı tüm sinyal listesini bize göstermek için -l
(liste) seçeneğiyle trap
da kullanabiliriz.
tuzak -l
Numaralı listemiz 64'te bitmesine rağmen, aslında 62 sinyal var. 32 ve 33 sinyalleri eksik. Linux'ta uygulanmazlar. Gerçek zamanlı iş parçacıklarını işlemek için gcc
derleyicisindeki işlevsellik ile değiştirildiler. SIGRTMIN
SIGRTMAX
her şey gerçek zamanlı sinyallerdir.
Farklı Unix benzeri işletim sistemlerinde farklı listeler göreceksiniz. Örneğin OpenIndiana'da 32 ve 33 sinyalleri ve toplam sayıyı 73'e çıkaran bir dizi ekstra sinyal mevcuttur.
Sinyallere ad, numara veya kısaltılmış adları ile başvurulabilir. Kısaltılmış adları, yalnızca baştaki "SIG" kaldırılmış olan adlarıdır.
Sinyaller birçok farklı nedenden dolayı yükseltilir. Onları deşifre edebilirseniz, amaçları adlarında yazılıdır. Bir sinyalin etkisi birkaç kategoriden birine girer:
- Sonlandır: İşlem sonlandırılır.
- Yoksay: Sinyal süreci etkilemez. Bu yalnızca bilgi amaçlı bir sinyaldir.
- Çekirdek: Bir döküm çekirdek dosyası oluşturulur. Bu genellikle, işlemin bellek ihlali gibi bir şekilde ihlal edilmesi nedeniyle yapılır.
- Durdur: İşlem durdurulur. Yani duraklatılır , sonlandırılmaz.
- Devam: Durdurulan bir işleme yürütmeye devam etmesini söyler.
Bunlar en sık karşılaşacağınız sinyallerdir.
- SIGHUP : Sinyal 1. SSH sunucusu gibi uzak bir ana bilgisayara bağlantı beklenmedik şekilde kesildi veya kullanıcı oturumu kapattı. Bu sinyali alan bir komut dosyası düzgün bir şekilde sonlandırılabilir veya uzak ana bilgisayara yeniden bağlanmayı deneyebilir.
- SIGINT : Sinyal 2. Kullanıcı, bir işlemi kapanmaya zorlamak için Ctrl+C kombinasyonuna basmıştır veya sinyal 2 ile birlikte
kill
komutu kullanılmıştır. Teknik olarak, bu bir kesme sinyalidir, sonlandırma sinyali değil, bir sinyal işleyici genellikle sonlandırılır. - SIGQUIT : Sinyal 3. Kullanıcı, bir işlemi çıkmaya zorlamak için Ctrl+D kombinasyonuna bastı veya
kill
komutu sinyal 3 ile kullanıldı. - SIGFPE : Signal 8. İşlem, sıfıra bölme gibi geçersiz (imkansız) bir matematiksel işlem gerçekleştirmeye çalıştı.
- SIGKILL : Sinyal 9. Bu, bir giyotinin sinyal eşdeğeridir. Onu yakalayamaz veya görmezden gelemezsiniz ve anında gerçekleşir. İşlem derhal sonlandırılır.
- SIGTERM : Signal 15. Bu,
SIGKILL
daha düşünceli versiyonudur.SIGTERM
ayrıca bir işlemin sonlandırılmasını söyler, ancak kapana kısılabilir ve işlem kapanmadan önce temizleme işlemlerini çalıştırabilir. Bu, zarif bir kapatma sağlar. Bu,kill
komutu tarafından oluşturulan varsayılan sinyaldir.
Komut Satırındaki Sinyaller
Bir sinyali yakalamanın bir yolu, sinyalin numarası veya adı ve sinyal alındığında olmasını istediğiniz bir yanıt ile trap
kullanmaktır. Bunu bir terminal penceresinde gösterebiliriz.
Bu komut SIGINT
sinyalini yakalar. Yanıt, terminal penceresine bir metin satırı yazdırmaktır. echo
ile -e
(çıkışları etkinleştir) seçeneğini kullanıyoruz, böylece “ \n
” biçim belirtecini kullanabiliriz.
trap 'echo -e "\nCtrl+c Algılandı." SIGINT
Ctrl+C kombinasyonuna her bastığımızda metin satırımız yazdırılır.
Bir sinyalde bir bindirmenin ayarlanıp ayarlanmadığını görmek için -p
(bindirme yazdır) seçeneğini kullanın.
tuzak -p İŞARET
trap
kullanmak aynı şeyi yapar.
Sinyali yakalanmamış, normal durumuna sıfırlamak için bir tire “ -
” ve yakalanan sinyalin adını kullanın.
tuzak - SIGINT
tuzak -p İŞARET
trap -p
komutundan çıkış olmaması, o sinyalde ayarlanmış bir tuzak olmadığını gösterir.
Komut Dosyalarında Sinyalleri Yakalama
Aynı genel format trap
komutunu bir komut dosyası içinde kullanabiliriz. Bu komut dosyası, SIGINT
, SIGQUIT
ve SIGTERM
olmak üzere üç farklı sinyali yakalar.
#!/bin/bash tuzak "echo I SIGINT sonlandırıldı; çık" SIGINT tuzak "echo I SIGQUIT sonlandırıldı; çıkış" SIGQUIT trap "echo I SIGTERM sonlandırıldı; çık" SIGTERM yankı $$ sayaç=0 doğru iken yapmak echo "Döngü numarası:" $((++sayaç)) uyku 1 tamamlamak
Üç trap
ifadesi, komut dosyasının en üstündedir. exit
komutunu sinyallerin her birine verilen yanıtın içine dahil ettiğimizi unutmayın. Bu, komut dosyasının sinyale tepki verdiği ve ardından çıktığı anlamına gelir.
Metni düzenleyicinize kopyalayın ve “simple-loop.sh” adlı bir dosyaya kaydedin ve chmod
komutunu kullanarak yürütülebilir hale getirin. Kendi bilgisayarınızda takip etmek istiyorsanız, bu makaledeki tüm komut dosyalarına bunu yapmanız gerekecektir. Her durumda uygun komut dosyasının adını kullanın.

chmod +x basit döngü.sh
Senaryonun geri kalanı çok basit. Komut dosyasının işlem kimliğini bilmemiz gerekiyor, bu yüzden komut dosyası bize bunu yansıtıyor. $$
değişkeni, betiğin işlem kimliğini tutar.
counter
adında bir değişken oluşturup sıfıra ayarlıyoruz.
while
döngüsü, zorla durdurulmadıkça sonsuza kadar çalışacaktır. counter
değişkenini arttırır, ekrana yansıtır ve bir saniye uyur.
Komut dosyasını çalıştıralım ve ona farklı sinyaller gönderelim.
./simple-loop.sh
“Ctrl+C”ye bastığımızda terminal penceresine mesajımız yazdırılır ve script sonlandırılır.
Tekrar çalıştıralım ve kill
komutunu kullanarak SIGQUIT
sinyalini gönderelim. Bunu başka bir terminal penceresinden yapmamız gerekecek. Kendi komut dosyanız tarafından bildirilen işlem kimliğini kullanmanız gerekir.
./simple-loop.sh
öldür -SIGQUIT 4575
Beklendiği gibi, komut dosyası gelen sinyali bildirir ve ardından sonlandırılır. Ve son olarak, konuyu kanıtlamak için SIGTERM
sinyali ile tekrar yapacağız.
./simple-loop.sh
öldür -SIGTERM 4584
Bir komut dosyasında birden çok sinyali yakalayabileceğimizi ve her birine bağımsız olarak tepki verebileceğimizi doğruladık. Tüm bunları ilginçten faydalıya doğru ilerleten adım, sinyal işleyicileri eklemektir.
Komut Dosyalarında Sinyalleri Kullanma
Yanıt dizesini, komut dosyanızdaki bir işlevin adıyla değiştirebiliriz. trap
komutu, sinyal algılandığında bu işlevi çağırır.
Bu metni bir düzenleyiciye kopyalayın ve “grace.sh” adlı bir dosya olarak kaydedin ve chmod
ile çalıştırılabilir hale getirin.
#!/bin/bash trap graceful_shutdown SIGINT SIGQUIT SIGTERM zarif_shutdown() { echo -e "\nGeçici dosya kaldırılıyor:" $temp_file rm -rf "$temp_file" çıkış } temp_file=$(mktemp -p /tmp tmp.XXXXXXXXXX) echo "Geçici dosya oluşturuldu:" $temp_file sayaç=0 doğru iken yapmak echo "Döngü numarası:" $((++sayaç)) uyku 1 tamamlamak
Komut dosyası, tek bir trap
ifadesi kullanarak üç farklı sinyal ( SIGHUP
, SIGINT
ve SIGTERM
) için bir tuzak kurar. Yanıt, graceful_shutdown()
işlevinin adıdır. Yakalanan üç sinyalden biri alındığında işlev çağrılır.
Komut dosyası, “/tmp” dizininde mktemp
kullanarak geçici bir dosya oluşturur. Dosya adı şablonu “tmp.XXXXXXXXXX” olduğundan, dosyanın adı “tmp” olacaktır. ardından on rastgele alfasayısal karakter gelir. Dosyanın adı ekranda yankılanır.
Komut dosyasının geri kalanı, bir counter
değişkeni ve sonsuz bir while
döngüsü ile öncekiyle aynıdır.
./grace.sh
Dosyaya kapanmasına neden olan bir sinyal gönderildiğinde, graceful_shutdown()
işlevi çağrılır. Bu, tek geçici dosyamızı siler. Gerçek dünya durumunda, betiğinizin gerektirdiği her türlü temizleme işlemini gerçekleştirebilir.
Ayrıca, kapana kısılmış tüm sinyallerimizi bir araya topladık ve bunları tek bir işlevle ele aldık. Sinyalleri tek tek yakalayabilir ve kendi özel işleyici işlevlerine gönderebilirsiniz.
Bu metni kopyalayın ve “triple.sh” adlı bir dosyaya kaydedin ve chmod
komutunu kullanarak yürütülebilir hale getirin.
#!/bin/bash trap sigint_handler SIGINT tuzak sigusr1_handler SIGUSR1 tuzak çıkış_handler EXIT function signt_handler() { ((++signt_count)) echo -e "\nSIGINT $sigint_count zaman(lar) aldı." if [[ "$sigint_count" -eq 3 ]]; sonra echo "Kapatma işlemi başlatılıyor." loop_flag=1 fi } function sigusr1_handler() { echo "SIGUSR1 $((++sigusr1_count)) zaman(lar)ını gönderdi ve aldı." } function exit_handler() { echo "Çıkış işleyicisi: Komut dosyası kapanıyor..." } yankı $$ sigusr1_count=0 signt_count=0 loop_flag=0 while [[ $loop_flag -eq 0 ]]; yapmak öldür -SIGUSR1 $$ uyku 1 tamamlamak
Komut dosyasının üst kısmında üç tuzak tanımlarız.
- Biri
SIGINT
yakalar vesigint_handler()
adlı bir işleyiciye sahiptir. - İkincisi,
SIGUSR1
adlı bir sinyali yakalar vesigusr1_handler()
adlı bir işleyici kullanır. - Üç numaralı tuzak,
EXIT
sinyalini yakalar. Bu sinyal, kapandığında betiğin kendisi tarafından yükseltilir.EXIT
için bir sinyal işleyici ayarlamak, komut dosyası sona erdiğinde her zaman çağrılacak bir işlev ayarlayabileceğiniz anlamına gelir (SinyalSIGKILL
ile öldürülmediği sürece). İşleyicimiz,exit_handler()
olarak adlandırılır.
SIGUSR1
ve SIGUSR2
, komut dosyalarınıza özel sinyaller gönderebilmeniz için sağlanan sinyallerdir. Onları nasıl yorumlayacağınız ve onlara nasıl tepki vereceğiniz tamamen size kalmış.
Sinyal işleyicileri şimdilik bir kenara bırakırsak, betiğin gövdesi size tanıdık gelecektir. İşlem kimliğini terminal penceresine yansıtır ve bazı değişkenler oluşturur. sigusr1_count
SIGINT
sayısını kaydeder ve sigint_count
, SIGUSR1
işlenme sayısını kaydeder. loop_flag
değişkeni sıfıra ayarlanır.
while
döngüsü sonsuz bir döngü değildir. loop_flag
değişkeni sıfır olmayan herhangi bir değere ayarlanırsa, döngü duracaktır. while
döngüsünün her dönüşü, SIGUSR1
sinyalini komut dosyasının işlem kimliğine göndererek bu komut dosyasına göndermek için kill
kullanır. Komut dosyaları kendilerine sinyal gönderebilir!
sigusr1_handler()
işlevi, sigusr1_count
değişkenini artırır ve terminal penceresine bir mesaj gönderir.
SIGINT
sinyali her alındığında, siguint_handler()
işlevi sigint_count
değişkenini artırır ve değerini terminal penceresine yansıtır.
sigint_count
değişkeni üçe eşitse, loop_flag
değişkeni bire ayarlanır ve terminal penceresine kullanıcıya kapatma işleminin başladığını bildiren bir mesaj gönderilir.
loop_flag
artık sıfıra eşit olmadığı için, while
döngüsü sona erer ve komut dosyası tamamlanır. Ancak bu eylem otomatik olarak EXIT
sinyalini yükseltir ve exit_handler()
işlevi çağrılır.
./üçlü.sh
Üç Ctrl+C basıldıktan sonra komut dosyası sonlandırılır ve otomatik olarak exit_handler()
işlevini çağırır.
Sinyalleri Okuyun
Sinyalleri yakalayarak ve bunlarla basit işleyici işlevleriyle ilgilenerek, beklenmedik bir şekilde sonlandırılsalar bile Bash betiklerinizi arkalarında toparlayabilirsiniz. Bu size daha temiz bir dosya sistemi sağlar. Ayrıca betiği bir sonraki çalıştırışınızda kararsızlığı önler ve betiğinizin amacına bağlı olarak güvenlik açıklarını bile önleyebilir.
İLGİLİ: Linux Sisteminizin Güvenliğini Lynis ile Denetleme