“Trap… INT TERM EXIT” gerçekten gerekli mi?


63

Birçok örnekler trapkullanım trap ... INT TERM EXITtemizleme görevler için. Fakat bu üç sigspec'in tümünü listelemek gerçekten gerekli mi?

Manuel diyor ki:

Bir SIGNAL_SPEC ÇIKIŞ ise (0) ARG kabuktan çıkışta yürütülür.

bence betiğin normal bitip bitmediğini veya aldığından SIGINTveya bitmesinden dolayı bitip bitmediğini uyguladım SIGTERM. Bir deney de inancımı doğrular:

$ cat ./trap-exit
#!/bin/bash
trap 'echo TRAP' EXIT
sleep 3
$ ./trap-exit & sleep 1; kill -INT %1
[1] 759
TRAP
[1]+  Interrupt               ./trap-exit
$ ./trap-exit & sleep 1; kill -TERM %1
[1] 773
TRAP
[1]+  Terminated              ./trap-exit

Öyleyse neden bu kadar çok örnek hepsini listeliyor INT TERM EXIT? Yoksa bir şeyi mi özledim ve bir tabanın EXITkaçıracağı bir durum var mı?


3
Ayrıca INT TERM EXITtemizleme kodu gibi bir özelliğe sahip olduğunda SIGTERMveya SIGINTalındığında iki kez çalıştırıldığını unutmayın .
maxschlepzig

Yanıtlar:


19

POSIX Spec sadece çevre yürütüldüğünde gibi bakmak gerekir yaklaşık EXIT tuzağı yürütülmesi ile sonuçlanan koşullar hakkında çok fazla söylemez.

Busybox'ın kül kabuğunda, tuzak çıkış testiniz SIGINT ya da SIGTERM nedeniyle çıkmadan önce 'TRAP' yankılanmıyor. Mevcut durumda bu şekilde çalışmayabilecek başka mermiler olduğundan şüpheleniyorum.

# /tmp/test.sh & sleep 1; kill -INT %1
# 
[1]+  Interrupt                  /tmp/test.sh
# 
# 
# /tmp/test.sh & sleep 1; kill -TERM %1
# 
[1]+  Terminated                 /tmp/test.sh
# 

3
dashayrıca sadece EXITaldığında tuzağa düşmez SIGINT/SIGTERM.
maxschlepzig

4
zshayrıca - bu nedenle, belki de sinyalleri eşleştiren bashtek kabuktur EXIT.
maxschlepzig

@ maxschlepzig aldığı zaman zshtuzağa düşmüyor , ancak EXITaldığı zaman başlıyor . EDIT: Sadece bunun kaç yaşında olduğunu farkettim ...INTTERM
JoL

27

Evet, bir fark var.

Bu komut, siz bastığınızda Enterveya gönderdiğinizde SIGINTveya SIGTERM:

trap '' EXIT
echo ' --- press ENTER to close --- '
read response

Bu komut, siz tuşuna bastığınızda çıkacaktır Enter:

trap '' EXIT INT TERM
echo ' --- press ENTER to close --- '
read response

* Sh , Bash ve Zsh ile test edilmiştir . (artık tuzağın çalışması için bir komut eklediğinizde sh ile çalışmaz)


Ayrıca @Shawn'ın söylediği de var: Ash ve Dash sinyalleri yakalamıyor EXIT.

Bu nedenle, sinyalleri güçlü bir şekilde ele almak için EXIT, tamamen hapsolmaktan kaçınmak ve bunun gibi bir şey kullanmak en iyisidir :

cleanup() {
    echo "Cleaning stuff up..."
    exit
}

trap cleanup INT TERM
echo ' --- press ENTER to close --- '
read var
cleanup

1
Temizleme ile çözüm doğru olanı yapar - çok zarif! mktempÇağrılarla yazılmış bas senaryolarım için bir deyim haline geldi .
Bjoern Dahlgren

2
Bu exitgerekli cleanupmi?
jarno

3
Bu, kodunuzda zamanından önce çıkmasına neden olan shellscript hataları varsa işe yaramaz.
ijw

2
@ iww: Bash ve Ksh’da bununla ERRbaşa çıkmak için tuzak kurabilirsiniz , ancak taşınabilir değildir .
Zaz

5
Bu çözüm, başka bir kabuk çağırdığında sağlam değildir. İşbirlikçi çıkışta beklemeyi ele almaz ; trap - INT TERM; kill -2 $$ebeveynin kabuğuna erken çıktığını söylemek için son temizlik satırı olarak isteyeceksiniz . Foobar.sh üst kabuğu, betiğinizi (foo.sh) çağırır ve daha sonra bar.sh'yi çağırırsa, INT / TERM foo.sh cihazınıza gönderildiyse, bar.sh'ın çalıştırılmasını istemezsiniz. trap cleanup EXITbu yayılımı otomatik olarak halledecektir, bu nedenle IMO en sağlam olanıdır. Ayrıca cleanupbetiğin sonunda aramak zorunda kalmayacaksınız anlamına gelir .
Nicholas Pipitone

12

Son cevabı daraltın, çünkü sorunları var:

# Our general exit handler
cleanup() {
    err=$?
    echo "Cleaning stuff up..."
    trap '' EXIT INT TERM
    exit $err 
}
sig_cleanup() {
    trap '' EXIT # some shells will call EXIT after the INT handler
    false # sets $?
    cleanup
}
trap cleanup EXIT
trap sig_cleanup INT QUIT TERM

Yukarıdaki puanlar:

INT ve TERM işleyicileri test ettiğimde benim için istifa etmiyorlar - hatayı idare ediyorlar, sonra kabuk çıkmaya geri dönüyor (ve bu çok şaşırtıcı değil). Bu nedenle temizlemenin daha sonra çıkmasını sağlarım ve sinyaller söz konusu olduğunda her zaman bir hata kodu kullanır (ve normal bir çıkış durumunda, hata kodunu korur).

Bash ile, INT işleyicisine çıkmanın EXIT işleyicisini de çağırdığı görülüyor, bu yüzden çıkış işleyicisini açıp kendim olarak adlandırıyorum (davranıştan bağımsız olarak herhangi bir kabukta çalışacak).

Çıkış yapıyorum, çünkü kabuk komut dosyaları en alt seviyeye gelmeden önce çıkabiliyor - sözdizimi hataları, set -e ve sıfırdan farklı bir dönüş, basitçe exit. Aşağıya inen bir kabuk komut dosyasına güvenemezsiniz.

SIGQUIT Ctrl- \ Eğer hiç denememişseniz. Bonus bonusu verir. Bu yüzden biraz belirsiz olsa bile, tuzağa düşürmeye değer olduğunu düşünüyorum.

Geçmiş deneyimler, (benim gibi), her zaman birkaç kez Ctrl-C'ye basarsanız, kabuk betiğinizin temizleme kısmının yarısını yakalayacağınızı söylüyor, bu yüzden bu çalışır, ancak her zaman istediğiniz kadar mükemmel olmaz.


2
Arayan çıkışa hangi sinyale neden olursa olsun, çıkış kodu olarak 1 trapalacaktır, arayan kişi ise SIGINT için 130, SIGTERM için 143, vb sig_cleanup() { err=$?; trap '' EXIT; (exit $err); cleanup; }.
musiphil

2
trap '' EXIT INT TERMTemizleme fonksiyonunun amacını netleştirebilir misiniz ? Bu, son paragrafta bahsettiğiniz temizliğin yanlışlıkla kullanıcı tarafından kesilmesini önlemek mi? EXITGereksiz değil mi?
Altı
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.