tuzak kullanarak onaylanmış çıkış


9

Ctrl+CKullanıcıdan bir onay isteyen sinyali yakalamaya çalışıyorum . Bindirme kısmı iyi çalışıyor. Ancak sinyal sıkıştığında, normal yürütmeye geri dönmez. Bunun yerine komut dosyasından çıkar. Kullanıcı no tuşuna bastığında yürütme nasıl devam ettirilir.

işte kodum

hell()
{
echo "Do you want to quit? Press 1 for yes and 0 for no";
read n;
if [ $n == 1 ]; then
exit 1;
fi
}

trap "hell" SIGINT

find /

Yanıtlar:


12

Ne oluyor

Ctrl+ Tuşuna bastığınızda C, SIGINTsinyal tüm ön plan işlem grubuna iletilir . Burada hem findişleme hem de çağrılan kabuk işlemine gönderilir. findhemen çıkarak tepki verir ve kabuk tuzağı çağırarak tepki verir.

Tuzaktaki kod geri dönerse (yani çağrı yapmazsa exit), yürütme, sinyal tarafından kesilen komuttan sonraki komutla devam eder. Burada, findkomut betiğin sonuna geldikten sonra, komut dosyası hemen yine de çıkar. Ancak başka bir komut ekleyerek 0 ile 1 girme arasındaki farkı görebilirsiniz:

find /
echo "find returned $?"

İstediğinizi yapmanın bir yolu (ama muhtemelen yapmamalısınız)

Ne istersen yapabilirsin; ama cevabımın bu kısmı, gerçek bir problemi çözmek yerine kabuk programlamayı keşfetmekle ilgili.

  • Bir tasarım meselesi olarak, yeniden başlatılabilir bir sinyal normalde kabuk betiklerinin olduğu nispeten basit programlarda normalde beklediğiniz şey değildir. Beklenti, Ctrl+ ' Cnın senaryoyu öldürmesi.
  • Aşağıda göreceğiniz gibi, kabuğun yeteneklerini biraz daha genişletiyor.

Eğer öldürme kaçınmak istiyorsanız find, size bunu başlatmak için gereken arka plan : find / &. Ardından normalden çıkmasını beklemek için waityerleşkeyi kullanın. Bir sinyal, waityaymak istediğiniz sinyali alana kadar bir döngüde çalıştırabileceğiniz yerleşik kesintiye neden olur. Sonra killişi öldürmek için kullanın .

hell () {
  echo "Do you want to quit? Press 1 for yes and 0 for no"
  read n
  if [ "$n" = 1 ]; then
    # Kill the job if it's running, then exit
    if [ -n "$job_pid" ]; then kill $job_pid; fi
    exit 1
  fi
}

job_pid=
trap "hell" SIGINT

# Start a demo job in the background
for i in 1 2 3 4 5; do date; sleep 1; done &
job_pid=$!
# Call wait in a loop; wait will return 0 if the job exits, and 128+$signum if interrupted by a signal.
while ! wait; do
  echo "resuming wait"
done
job_pid=
echo last exit code: $?

Kabukta bu yaklaşımın sınırlamaları vardır:

  • Bir yarış koşulu var: iş bittikten hemen sonra Ctrl+ çizgisine basmadan + tuşuna basarsanız , sinyal işleyici öldürmeye çalışacak , ancak işlem artık mevcut değil (bir zombi olarak bile , zaten hasat ettiğinden) ve süreç Kimlik başka bir işlem tarafından yeniden kullanılmış olabilir. Bu, kabukta kolayca düzeltilemez (belki bir işleyici ayarlayarak ?).Cjob_pid=$jobpidwaitSIGCHLD
  • İşten iade durumuna ihtiyacınız varsa, wait $job_pidformu kullanmanız gerekir . Ama o zaman “ waitbir sinyalle kesildi” yi “iş bir sinyalle öldürüldü” (ne de “kendi statüsüyle geri dönüş durumu ≥128” ile bitirilen işten) ayırt edemezsiniz, ama bu kabukta genel bir gerçektir programlama).
  • Bu, eğer birden fazla subjobs'a kolayca uzanmayacaktır. Çoğu kabuk uygulamasında temellerin ötesine geçtiğinizde tuzakların ve sinyallerin davranışının genellikle şaşırtıcı olduğunu unutmayın (sadece ksh bunu iyi yapar).

Bu sınırlamaların üstesinden gelmek için Perl veya Python gibi meraklı bir dil kullanın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.