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
killkomutu 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
killkomutu 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,
SIGKILLdaha düşünceli versiyonudur.SIGTERMayrı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,killkomutu 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
tamamlamakKomut dosyasının üst kısmında üç tuzak tanımlarız.
- Biri
SIGINTyakalar vesigint_handler()adlı bir işleyiciye sahiptir. - İkincisi,
SIGUSR1adlı bir sinyali yakalar vesigusr1_handler()adlı bir işleyici kullanır. - Üç numaralı tuzak,
EXITsinyalini yakalar. Bu sinyal, kapandığında betiğin kendisi tarafından yükseltilir.EXITiçin bir sinyal işleyici ayarlamak, komut dosyası sona erdiğinde her zaman çağrılacak bir işlev ayarlayabileceğiniz anlamına gelir (SinyalSIGKILLile ö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

