Linux'ta Bash Komut Dosyalarında Hatalar Nasıl Yakalanır
Yayınlanan: 2022-08-27
Varsayılan olarak, Linux'ta bir Bash betiği bir hata bildirir ancak çalışmaya devam eder. Daha sonra ne olması gerektiğine karar verebilmeniz için hataları kendiniz nasıl ele alacağınızı gösteriyoruz.
Komut Dosyalarında Hata İşleme
Hataları işleme, programlamanın bir parçasıdır. Kusursuz kod yazsanız bile, yine de hata koşullarıyla karşılaşabilirsiniz. Siz yazılım yükledikçe ve kaldırdıkça, dizinler oluşturdukça ve yükseltme ve güncellemeler yaptıkça bilgisayarınızdaki ortam zamanla değişir.
Örneğin, önceden sorunsuz çalışan bir komut dosyası, dizin yolları değişirse veya bir dosyadaki izinler değiştirilirse zorluklarla karşılaşabilir. Bash kabuğunun varsayılan eylemi, bir hata mesajı yazdırmak ve komut dosyasını yürütmeye devam etmektir. Bu tehlikeli bir varsayılandır.
Başarısız olan eylem, komut dosyanızda daha sonra gerçekleşecek başka bir işlem veya eylem için kritikse, bu kritik eylem başarılı olmayacaktır. Bunun ne kadar feci olduğu, senaryonuzun ne yapmaya çalıştığına bağlıdır.
Daha sağlam bir şema, hataları tespit eder ve komut dosyasının kapatılması veya arıza durumunu düzeltmeye çalışması gerektiğinde çalışmasına izin verir. Örneğin, bir dizin veya dosya eksikse, komut dosyasının bunları yeniden oluşturması tatmin edici olabilir.
Komut dosyası kurtarılamayan bir sorunla karşılaşırsa kapatılabilir. Komut dosyasının kapatılması gerekiyorsa, geçici dosyaları kaldırmak veya hata durumunu ve kapatma nedenini bir günlük dosyasına yazmak gibi gerekli temizleme işlemlerini gerçekleştirme şansına sahip olabilir.
Çıkış Durumunu Algılama
Komutlar ve programlar, sonlandırıldıklarında işletim sistemine gönderilen bir değer oluşturur. Buna çıkış durumları denir. Hata yoksa sıfır, bir hata oluştuysa sıfır olmayan bir değere sahiptir.
Komut dosyasının kullandığı komutların çıkış durumunu (dönüş kodu olarak da bilinir) kontrol edebilir ve komutun başarılı olup olmadığını belirleyebiliriz.
Bash'de sıfır, true değerine eşittir. Komuttan gelen yanıt doğru dışında bir şeyse, bir sorun olduğunu biliyoruz ve uygun eylemi yapabiliriz.
Bu komut dosyasını bir düzenleyiciye kopyalayın ve “bad_command.sh” adlı bir dosyaya kaydedin.
#!/bin/bash if ( ! bad_command ); sonra echo "bad_command bir hata işaretledi." çıkış 1 fi
Komut dosyasını chmod
komutuyla yürütülebilir hale getirmeniz gerekir. Bu, herhangi bir komut dosyasını yürütülebilir hale getirmek için gerekli bir adımdır, bu nedenle komut dosyalarını kendi makinenizde denemek istiyorsanız, bunu her biri için yapmayı unutmayın. Her durumda uygun komut dosyasının adını değiştirin.
chmod +x bad_command.sh
Komut dosyasını çalıştırdığımızda beklenen hata mesajını görüyoruz.
./bad_command.sh
“bad_command” diye bir komut yok, betik içindeki bir fonksiyonun adı da yok. Yürütülemez, bu nedenle yanıt sıfır değildir . Yanıt sıfır değilse—burada ünlem işareti mantıksal NOT
operatörü olarak kullanılır— if
ifadesinin gövdesi yürütülür.
Gerçek dünyadaki bir komut dosyasında bu, örneğimizin yaptığı gibi komut dosyasını sonlandırabilir veya hata durumunu düzeltmeye çalışabilir.
exit 1
satırı gereksiz gibi görünebilir. Sonuçta, senaryoda başka bir şey yok ve yine de sona erecek. Ancak exit
komutunu kullanmak, bir çıkış durumunu kabuğa geri iletmemizi sağlar. Komut dosyamız ikinci bir komut dosyası içinden çağrılırsa, o ikinci komut dosyası bu komut dosyasının hatalarla karşılaştığını bilir.
Bir komutun çıkış durumuyla mantıksal OR
operatörünü kullanabilir ve ilk komuttan sıfır olmayan bir yanıt varsa betiğinizde başka bir komut veya işlev çağırabilirsiniz.
komut_1 || komut_2
Bu, ilk komutun OR
ikincisinin çalıştırılması nedeniyle çalışır. En soldaki komut önce çalıştırılır. Başarılı olursa, ikinci komut yürütülmez. Ancak ilk komut başarısız olursa, ikinci komut yürütülür. Böylece kodu şu şekilde yapılandırabiliriz. Bu "mantıksal-or./sh."
#!/bin/bash error_handler() { echo "Hata: ($?) $1" çıkış 1 } kötü_komut || error_handler "bad_command başarısız oldu, Satır: ${LINENO}"
error_handler
adında bir fonksiyon tanımladık. Bu, $?
değişkeninde tutulan başarısız komutun çıkış durumunu yazdırır. ve işlev çağrıldığında kendisine iletilen bir metin satırı. Bu, $1
değişkeninde tutulur. İşlev, komut dosyasını bir çıkış durumuyla sonlandırır.
Komut dosyası, açıkça başarısız olan bad_command
çalıştırmayı dener, bu nedenle mantıksal OR
operatörünün sağındaki komut, ||
, Idam edildi. Bu, error_handler
işlevini çağırır ve başarısız olan komutu adlandıran ve başarısız olan komutun satır numarasını içeren bir dize iletir.
Hata işleyici mesajını görmek için betiği çalıştıracağız ve ardından echo kullanarak betiğin çıkış durumunu kontrol edeceğiz.
./mantıksal-or.sh
yankı $?
Küçük error_handler
işlevimiz, bad_command
çalıştırma girişiminin çıkış durumunu, komutun adını ve satır numarasını sağlar. Bu, bir komut dosyasında hata ayıklarken yararlı bilgilerdir.

Komut dosyasının çıkış durumu birdir. error_handler
tarafından bildirilen 127 çıkış durumu "komut bulunamadı" anlamına gelir. İstesek bunu exit
komutuna geçirerek betiğin çıkış durumu olarak kullanabiliriz.
Başka bir yaklaşım, çıkış durumunun farklı olası değerlerini kontrol etmek ve bu tür yapıyı kullanarak buna göre farklı eylemler gerçekleştirmek için error_handler
genişletmek olacaktır:
çıkış_kodu=$? if [ $exit_code -eq 1 ]; sonra echo "İşletime izin verilmiyor" elif [ $exit_code -eq 2 ]; sonra echo "Kabuk yerleşiklerinin kötüye kullanılması" . . . elif [ $durum -eq 128 ]; sonra echo "Geçersiz argüman" fi
Bir Çıkışı Zorlamak İçin Seti Kullanma
Bir hata olduğunda betiğinizin çıkmasını istediğinizi biliyorsanız, bunu yapmaya zorlayabilirsiniz. bu, herhangi bir temizleme veya daha fazla hasar olasılığını da ortadan kaldırdığınız anlamına gelir, çünkü komut dosyanız bir hata algıladığı anda sona erer.
Bunu yapmak için -e
(hata) seçeneği ile set
komutunu kullanın. Bu, komut dosyasına bir komut başarısız olduğunda çıkmasını söyler veya sıfırdan büyük bir çıkış kodu döndürür. Ayrıca -E
seçeneğinin kullanılması, kabuk işlevlerinde hata algılama ve yakalama çalışmalarını sağlar.
Başlatılmamış değişkenleri de yakalamak için -u
(unset) seçeneğini ekleyin. Borulu dizilerde hataların algılandığından emin olmak için -o pipefail
seçeneğini ekleyin. Bu olmadan, sıralı komut dizisinin çıkış durumu, dizideki son komutun çıkış durumudur. Borulu sıranın ortasındaki başarısız bir komut algılanmayacaktır. -o pipefail
seçeneği, seçenekler listesinde gelmelidir.
Komut dosyanızın en üstüne eklenecek sıra:
set -Eeuo boru arızası
İşte içinde unset-var.sh olan ve içinde unset değişkeni olan kısa bir betik.
#!/bin/bash set -Eeou boru arızası echo "$unset_variable" echo "Bu satırı görüyor muyuz?"
Komut dosyasını çalıştırdığımızda, unset_variable başlatılmamış bir değişken olarak tanınır ve komut dosyası sonlandırılır.
./unset-var.sh
İkinci echo
komutu hiçbir zaman yürütülmez.
Hatalı Tuzağı Kullanma
Bash trap komutu, belirli bir sinyal yükseldiğinde çağrılması gereken bir komutu veya işlevi atamanıza olanak tanır. Tipik olarak bu, Ctrl+C tuş bileşimine bastığınızda ortaya çıkan SIGINT
gibi sinyalleri yakalamak için kullanılır. Bu komut dosyası "sigint.sh."
#!/bin/bash trap "echo -e '\nCtrl+c' ile sonlandırıldı; çıkış" SIGINT sayaç=0 doğru iken yapmak echo "Döngü numarası:" $((++sayaç)) uyku 1 tamamlamak
trap
komutu bir echo
komutu ve exit
komutu içerir. SIGINT
yükseltildiğinde tetiklenecektir. Komut dosyasının geri kalanı basit bir döngüdür. Komut dosyasını çalıştırır ve Ctrl+C'ye basarsanız, trap
tanımından gelen mesajı görürsünüz ve komut dosyası sonlandırılır.
./sigint.sh
Hataları oluştukları anda yakalamak için ERR
sinyali ile trap
kullanabiliriz. Bunlar daha sonra bir komuta veya işleve beslenebilir. Bu "trap.sh." error_handler
adlı bir işleve hata bildirimleri gönderiyoruz.
#!/bin/bash tuzak 'error_handler $? $LINENO' HATA error_handler() { echo "Hata: ($1) $2'da oluştu" } ana() { echo "Main() fonksiyonunun içinde" bad_command ikinci üçüncü $ çıkış? } ikinci() { echo "Main() çağrısından sonra" echo "İkinci () işlevinde" } üçüncü() { echo "Üçüncü() işlevin içinde" } ana
Komut dosyasının büyük kısmı, second
ve third
işlevleri çağıran main
işlevin içindedir. Bir hatayla karşılaşıldığında - bu durumda, bad_command
olmadığı için - trap
ifadesi hatayı error_handler
işlevine yönlendirir. Başarısız komuttan çıkış durumunu ve satır numarasını error_handler
işlevine iletir.
./trap.sh
error_handler
işlevimiz, hatanın ayrıntılarını terminal penceresine listeler. İsterseniz, komut dosyasının sonlandırılması için işleve bir exit
komutu ekleyebilirsiniz. Veya farklı hatalar için farklı eylemler gerçekleştirmek için bir dizi if/elif/fi
deyimi kullanabilirsiniz.
Bazı hataları düzeltmek mümkün olabilir, diğerleri komut dosyasının durmasını gerektirebilir.
Son Bir İpucu
Hataları yakalamak, genellikle yanlış gidebilecek şeyleri önceden almak ve ortaya çıkması durumunda bu olasılıkları ele almak için kod koymak anlamına gelir. Bu, betiğinizin yürütme akışının ve dahili mantığının doğru olduğundan emin olmanın yanı sıra.
Komut dosyanızı çalıştırmak için bu komutu kullanırsanız, Bash komut dosyası yürütülürken size bir izleme çıktısı gösterecektir:
bash -x komut dosyanız.sh
Bash, izleme çıktısını terminal penceresinde yazar. Her komutu bağımsız değişkenleriyle birlikte gösterir - varsa. Bu, komutlar genişletildikten sonra ancak yürütülmeden önce olur.
Bu, anlaşılması zor hataların izlenmesinde muazzam bir yardım olabilir.
İLGİLİ: Çalıştırmadan Önce Linux Bash Komut Dosyasının Sözdizimini Doğrulama