"जाल ... INT अवधि बाहर निकलना" वास्तव में आवश्यक है?


63

सफाई कार्यों के लिए trapउपयोग के trap ... INT TERM EXITलिए कई उदाहरण । लेकिन क्या वास्तव में तीनों सिगस्पेक्ट्स को सूचीबद्ध करना आवश्यक है?

मैनुअल कहता है:

यदि कोई SIGNAL_SPEC EXIT (0) है तो ARG को शेल से बाहर निकलने पर निष्पादित किया जाता है।

जो मुझे लगता है कि यह लागू होता है कि क्या स्क्रिप्ट सामान्य रूप से समाप्त हुई या यह समाप्त हो गई क्योंकि यह प्राप्त हुई SIGINTया SIGTERM। एक प्रयोग भी मेरे विश्वास की पुष्टि करता है:

$ 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

तो फिर इतने सारे उदाहरण सभी की सूची क्यों बनाते हैं INT TERM EXIT? या मैंने कुछ मिस किया है और क्या कोई ऐसा मामला है जहां एक एकमात्र EXITयाद आती है?


3
यह भी ध्यान रखें कि INT TERM EXITक्लीनअप कोड की तरह एक कल्पना के साथ दो बार निष्पादित किया जाता है SIGTERMया SIGINTप्राप्त होने पर।
मैक्सक्लेपज़िग

जवाबों:


19

POSIX कल्पना की स्थिति से बाहर निकलें जाल को क्रियान्वित करने, केवल बारे में क्या अपने पर्यावरण जब यह मार डाला जाता है की तरह लग रहे चाहिए जिसका परिणाम के बारे में ज्यादा नहीं कहना है।

बिजीबॉक्स के ऐश शेल में, आपका ट्रैप-एग्जिट टेस्ट SIGINT या SIGTERM के कारण बाहर निकलने से पहले 'TRAP' को इको नहीं करता है। मुझे लगता है कि अस्तित्व में अन्य गोले हैं जो उस तरह से भी काम नहीं कर सकते हैं।

# /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
dashयह भी EXITप्राप्त होने पर बस नहीं फंसती है SIGINT/SIGTERM
मैक्सक्लेपज़िग

4
zshसाथ ही - इस प्रकार, शायद bashएकमात्र ऐसा शेल है जहां EXITसिग्नल से मिलान भी होता है।
मैक्सक्लेपजिग

@maxschlepzig प्राप्त होने zshपर नहीं फंसता है , लेकिन यह प्राप्त होने पर करता है । संपादित करें: मैंने अभी देखा कि यह कितना पुराना था ...EXITINTTERM
जोएल

27

हां, वहां एक अंतर है।

जब आप दबाएंगे Enter, या भेजेंगे SIGINTया SIGTERM: यह स्क्रिप्ट बाहर निकल जाएगी

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

प्रेस करते ही यह स्क्रिप्ट बाहर निकल जाएगी Enter:

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

* , बैश और ज़श में परीक्षण किया गया । ( जब आप ट्रैप चलाने के लिए कमांड जोड़ते हैं तो में काम नहीं करता )


वहाँ भी क्या @ शॉन ने कहा: ऐश और डैश संकेतों के साथ नहीं फंसते EXIT

इसलिए, संकेतों को मजबूती से संभालने के लिए, EXITपूरी तरह से फंसने से बचना सबसे अच्छा है , और इस तरह से कुछ का उपयोग करें:

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

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

1
सफाई के साथ समाधान सही काम करता है - बहुत सुरुचिपूर्ण! यह mktempकॉल के साथ मेरी बैश स्क्रिप्ट के लिए एक मुहावरा बन गया है ।
बज़र्न डाहलग्रेन

2
क्या यह exitआवश्यक है cleanup?
जर्नो

3
यह काम नहीं करता है यदि आपके पास अपने कोड में शेलस्क्रिप्ट त्रुटि है जो समय से पहले बाहर निकलने का कारण बनती है।
3

2
@ जीज: बाश और क्ष में, आप इसे ERRसंभालने के लिए फंस सकते हैं , लेकिन यह पोर्टेबल नहीं है
ज़ाज़

5
जब कोई अन्य शेल इसे कॉल करता है तो यह समाधान मजबूत नहीं होता है। यह सहकारी निकास पर प्रतीक्षा को संभालता नहीं है ; आप trap - INT TERM; kill -2 $$समय-समय पर बाहर निकलने वाले मूल शैल को बताने के लिए सफाई की अंतिम पंक्ति के रूप में चाहते हैं । यदि कोई पेरेंट शेल foobar.sh आपकी स्क्रिप्ट (foo.sh) को कॉल करता है, और फिर bar.sh को कॉल करता है, तो आप नहीं चाहते हैं कि INT / TERM आपके foo.sh को भेजे जाने पर बार निष्पादित करें। trap cleanup EXITइस प्रसार को स्वचालित रूप से संभाल लेगा, इसलिए यह IMO सबसे अधिक मजबूत है। इसका मतलब यह भी है कि आपको cleanupस्क्रिप्ट के अंत में कॉल नहीं करना होगा ।
निकोलस पिपिटोन

12

अंतिम उत्तर को परिष्कृत करना, क्योंकि इसमें समस्याएं हैं:

# 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

ऊपर दिए गए बिंदु:

INT और TERM हैंडलर मेरे लिए तब नहीं जाते जब मैं परीक्षण करता हूं - वे त्रुटि को संभालते हैं, फिर शेल बाहर निकलते हैं (और यह आश्चर्यजनक नहीं है)। इसलिए मैं यह सुनिश्चित करता हूं कि क्लीनअप बाद में बाहर निकलता है, और संकेतों के मामले में हमेशा एक त्रुटि कोड का उपयोग होता है (और सामान्य निकास के अन्य मामले में, त्रुटि कोड को संरक्षित करता है)।

बैश के साथ, ऐसा लगता है कि INT हैंडलर में बाहर निकलने को भी EXIT हैंडलर कहते हैं, इसलिए मैं बाहर निकलने वाले हैंडलर को अनट्रैप करता हूं और इसे खुद कहता हूं (जो व्यवहार की परवाह किए बिना किसी भी शेल में काम करेगा)।

मैं बाहर निकलता हूं क्योंकि शेल स्क्रिप्ट नीचे पहुंचने से पहले बाहर निकल सकती हैं - सिंटैक्स त्रुटियां, सेट-ई और नॉनजरो रिटर्न, बस बाहर निकलने को बुलावा देना। आप एक गोले पर नीचे तक भरोसा नहीं कर सकते।

यदि आपने कभी कोशिश नहीं की है तो SIGQUIT Ctrl- \ है। आप एक बोनस coredump हो जाता है। तो मुझे लगता है कि यह फँसने लायक भी है, भले ही यह थोड़ा अस्पष्ट हो।

पिछला अनुभव कहता है कि यदि आप (मेरे जैसे) हमेशा Ctrl-C दबाते हैं, तो आप कभी-कभी इसे अपनी शेल स्क्रिप्ट के क्लीनअप भाग के माध्यम से आधे रास्ते से पकड़ लेंगे, इसलिए यह हमेशा वैसा ही काम करता है, जैसा आप चाहते हैं।


2
कॉल करने वाले को एक्ज़िट कोड के रूप में केवल 1 मिलेगा, चाहे सिग्नल किस भी एग्ज़िट का कारण बने, जबकि trapकॉल करने वाले को SIGINT के लिए 130, SIGTERM के लिए 143 आदि मिलेंगे, इसलिए मैं सही एक्ज़िट कोड को कैप्चर और पास करूँगा sig_cleanup() { err=$?; trap '' EXIT; (exit $err); cleanup; }:।
मुशीफिल

2
क्या आप trap '' EXIT INT TERMक्लीनअप फ़ंक्शन के उद्देश्य को स्पष्ट कर सकते हैं ? क्या यह सफाई के आकस्मिक उपयोगकर्ता व्यवधान को रोकने के लिए है जिसका आपने अंतिम पैराग्राफ में उल्लेख किया था? क्या EXITअतिरेक नहीं है ?
छह
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.