SIGINT और समान को फँसाने पर बाहर निकलें कोड रखें?


14

अगर मैं http://linuxcommand.org/wss0160.php#traptrap पर वर्णित उदाहरण का उपयोग करता हूं हूं, बाहर निकलने से पहले ctrl-c (या समान) और क्लीनअप को पकड़ने के लिए तो मैं बाहर निकले कोड को बदल रहा हूं।

अब यह शायद वास्तविक दुनिया में अंतर नहीं करेगा (उदाहरण के लिए, क्योंकि बाहर निकलने वाले कोड पोर्टेबल नहीं हैं और उसके शीर्ष पर हमेशा नहीं होते हैं जैसा कि डिफ़ॉल्ट निकास कोड में चर्चा की जाती है जब प्रक्रिया समाप्त हो जाती है? ) लेकिन फिर भी मैं सोच रहा हूं कि क्या वहाँ है? वास्तव में इसे रोकने और इसके बजाय बाधित स्क्रिप्ट के लिए डिफ़ॉल्ट त्रुटि कोड वापस करने का कोई तरीका नहीं है?

उदाहरण (बाश में, लेकिन मेरे प्रश्न को बाश-विशिष्ट नहीं माना जाना चाहिए):

#!/bin/bash
trap 'echo EXIT;' EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. ' _
trap 'echo SIGINT; exit 1;' INT
read -p 'If you ctrl-c me now my return code will be 1. ' _

आउटपुट:

$ ./test.sh # doing ctrl-c for 1st read
If you ctrl-c me now my return code will be the default for SIGTERM.
$ echo $?
130
$ ./test.sh # doing ctrl-c for 2nd read
If you ctrl-c me now my return code will be the default for SIGTERM.
If you ctrl-c me now my return code will be 1. SIGINT 
EXIT
$ echo $?
1

(इसे और अधिक POSIX- अनुरूप बनाने के लिए निकालने का संपादन किया गया।)

(इसके बजाय इसे बैश स्क्रिप्ट बनाने के लिए फिर से संपादित किया गया, मेरा सवाल हालांकि शेल-विशिष्ट नहीं है।)

गैर-पोर्टेबल "SIGINT" के पक्ष में जाल के लिए पोर्टेबल "INT" का उपयोग करने के लिए संपादित।

बेकार घुंघराले ब्रेसिज़ को हटाने और संभावित समाधान जोड़ने के लिए संपादित।

अपडेट करें:

मैंने इसे अभी हल किया है केवल कुछ त्रुटि कोड के साथ बाहर निकलकर हार्डकोड और फंसाने वाला EXIT। यह कुछ प्रणालियों पर समस्याग्रस्त हो सकता है क्योंकि त्रुटि कोड भिन्न हो सकता है या EXIT जाल संभव नहीं है, लेकिन मेरे मामले में यह ठीक है।

trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM

आपकी स्क्रिप्ट थोड़ी अजीब लगती है: आप readवर्तमान कॉपीरो से पढ़ने के लिए trap cmd SIGINTकहते हैं और यह काम नहीं करेगा क्योंकि मानक कहता है कि आपको उपयोग करना चाहिए trap cmd INT
शास्त्री

हाँ, POSIX के तहत यह निश्चित रूप से SIG- उपसर्ग के बिना है।
phk

उफ़, लेकिन फिर "रीड-पी" का समर्थन नहीं किया जाएगा, इसलिए मैं इसे बैश के लिए अनुकूलित करने जा रहा हूं।
phk

@ सामान्य रूप से: मुझे नहीं पता कि आपका "कोप्रोसेस" के साथ क्या मतलब है।
phk

खैर, कॉर्न शेल मैन पेज कहता read -pहै कि वर्तमान कोप्रोसेस से इनपुट पढ़ता है।
शास्त्री

जवाबों:


4

आपको बस अपने क्लीनअप हैंडलर के अंदर EXIT हैंडलर को बदलना है । यहाँ एक उदाहरण है:

#!/bin/bash
cleanup() {
    echo trapped exit
    trap 'exit 0' EXIT
}
trap cleanup EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. '

क्या आपका मतलब trap cleanup INTइसके बजाय था trap cleanup EXIT?
जेफ स्कालर

मुझे लगता है कि मेरा मतलब EXIT था। जब निकास को आखिरकार कहा जाता है, हालांकि ऐसा किया जाता है, हम वापसी के साथ बाहर निकलने के लिए जाल को बदलते हैं 0. मुझे विश्वास नहीं होता कि सिग्नल हैंडलर पुनरावर्ती हैं।
रॉकी

ठीक है, आपके उदाहरण में मैं (SIG) INT को नहीं फँसा रहा हूँ जो वास्तव में वही है जो मैं कुछ सफाई करने के लिए चाहता हूँ, भले ही उपयोगकर्ता ctrl-c के माध्यम से मेरी संवादात्मक स्क्रिप्ट से बाहर निकल रहा हो।
phk

@ एफके ओके। मुझे लगता है कि यद्यपि आपको यह विचार मिलता है कि कैसे बाहर निकलने के लिए मजबूर किया जाए 0 या कुछ अन्य मूल्य जो मैंने इकट्ठा किया था वह समस्या थी। मुझे लगता है कि आप अपने असली सफाई हैंडलर के अंदर जाल EXIT सेटिंग डालने के लिए कोड को समायोजित करने में सक्षम होंगे जिसे SIGINT द्वारा बुलाया जाता है।
चट्टानी

@ क्रॉ: मेरा लक्ष्य एक ट्रैप हैंडलर का था, जबकि एग्जिट कोड को नहीं बदलना जो कि मैं आमतौर पर हैंडलर के बिना होता। अब मैं केवल आपके द्वारा सामान्य रूप से प्राप्त होने वाले निकास कोड को वापस कर सकता था, लेकिन समस्या यह थी कि मुझे इन मामलों में सटीक निकास कोड नहीं पता है (जैसा कि मैंने जिस थ्रेड में जोड़ा था और meuh से पोस्ट काफी जटिल है)। आपकी पोस्ट अभी भी उपयोगी थी, मैंने ट्रैप हैंडलर को गतिशील रूप से पुनर्परिभाषित करने के बारे में नहीं सोचा था।
phk

9

दरअसल, बैश readद्वारा संचालित कमांड को बाधित करने के लिए बैश के आंतरिक को बाधित करना थोड़ा अलग लगता है। आम तौर पर, जब आप प्रवेश करते हैं trap, $?सेट किया जाता है और आप इसे संरक्षित कर सकते हैं और समान मूल्य के साथ बाहर निकल सकते हैं:

trap 'rc=$?; echo $rc SIGINT; exit $rc' INT
trap 'rc=$?; echo $rc EXIT; exit $rc' EXIT

यदि आपकी स्क्रिप्ट को एक कमांड को निष्पादित करते समय बाधित किया जाता है जैसे कि sleep या यहां तक ​​कि बिलिन जैसा wait, तो आप देखेंगे

130 SIGINT
130 EXIT

और बाहर निकलने का कोड 130 है। हालांकि, read -pऐसा लगता है $?कि यह 0 है (वैसे भी मेरे संस्करण 4.3.42 पर बैश है)।


readमेरी रिलीज़ में परिवर्तन फ़ाइल के अनुसार संकेतों की हैंडलिंग कार्य प्रगति पर हो सकती है ... (/ usr / share / doc / bash / CHANGES)

इस संस्करण के बीच परिवर्तन, बैश-4.3-अल्फा, और पिछला संस्करण, बैश-4.2-रिलीज़।

  1. बैश में नई सुविधाएँ

    आर। जब पॉज़िक्स मोड में, `रीड 'एक फंसे सिग्नल द्वारा बाधित होता है। ट्रैप हैंडलर को चलाने के बाद, रिटर्न 128 + सिग्नल पढ़ें और किसी भी आंशिक रूप से पढ़े गए इनपुट को फेंक दें।


ठीक है, यह वास्तव में अजीब है। यह बैश 4.3.42 (साइबरविन के तहत) पर इंटरेक्टिव शेल पर 130 है, 0 उसी शेल के तहत जब कोई स्क्रिप्ट और पोसिक्स मोड में है या कोई फर्क नहीं पड़ता है। लेकिन फिर डैश और बिजीबॉक्स के तहत यह हमेशा 1. है
phk

मैंने POSIX मोड को एक जाल के साथ आज़माया, जो बाहर नहीं निकलता, और यह फिर से शुरू होता है read, जैसा कि CHANGES फ़ाइल में लिखा गया है (मेरे उत्तर में जोड़ा गया)। इसलिए, यह कार्य प्रगति पर हो सकता है।
मयूह

बाहर निकलने का कोड 130 100% गैर-पोर्टेबल है। जबकि बॉर्न शेल 128 + signoसंकेतों के लिए निकास कोड के रूप में उपयोग करता है, ksh93 उपयोग करता है 256 + signo। पोसिक्स कहता है: 128 से ऊपर कुछ ....
स्किल्ली

@ सच में सच है, जैसा कि मैंने मूल पोस्ट ( unix.stackexchange.com/questions/99112 ) से जुड़े धागे में नोट किया है ।
phk

6

$?ट्रैप हैंडलर में प्रवेश पर कोई भी सामान्य सिग्नल निकास कोड उपलब्ध होगा :

sig_handler() {
    exit_status=$?  # Eg 130 for SIGINT, 128 + (2 == SIGINT)
    echo "Doing signal-specific up"
    exit "$exit_status"
}
trap sig_handler INT HUP TERM QUIT

यदि एक अलग EXIT जाल है, तो आप एक ही कार्यप्रणाली का उपयोग कर सकते हैं: तुरंत सिग्नल हैंडलर से पारित निकास की स्थिति को रखें (यदि कोई है) तो सफाई करें, फिर सहेजे गए निकास की स्थिति वापस करें।


यह अधिकांश गोले पर लागू होता है? बहुत अच्छा। localहालांकि POSIX नहीं है।
phk

1
संपादित। मैंने अन्य के अलावा परीक्षण नहीं किया है {ba,z}sh। AFAIK, यह सबसे अच्छा है जो किया जा सकता है, भले ही।
टॉम हेल

यह डैश में काम नहीं करता है ( $?1 जो भी प्राप्त संकेत है)।
मूनस्वीप

2

सिर्फ कुछ त्रुटि कोड लौटाएं SIGINT द्वारा बाहर निकलने का अनुकरण करने के लिए पर्याप्त नहीं है। मुझे आश्चर्य है कि अब तक किसी ने इसका उल्लेख नहीं किया। आगे की पढाई: https://www.cons.org/cracauer/sigint.html

उचित तरीका है:

for sig in EXIT ABRT HUP INT PIPE QUIT TERM; do
    trap "cleanup;
          [ $sig  = EXIT ] && normal_exit_only_cleanup;
          [ $sig != EXIT ] && trap - $sig EXIT && kill -s $sig $$
         " $sig
done

यह बैश, डैश और zsh के साथ काम करता है। आगे पोर्टेबिलिटी के लिए, आपको संख्यात्मक सिग्नल विनिर्देशों का उपयोग करने की आवश्यकता है (दूसरी तरफ, zsh को इसके लिए एक स्ट्रिंग पैरामीटर की उम्मीद हैkill कमांड के ...)

EXITसंकेत के विशेष उपचार पर भी ध्यान दें । यह कुछ गोले (अर्थात् बाश) के कारण जाल को निष्पादित करता हैEXIT किसी भी संकेत के लिए (संभवतः उस संकेत पर परिभाषित जाल के बाद)। का रीसेटEXITजाल के रोकता है।

केवल "सामान्य" निकास पर निष्पादन कोड

चेक [ $sig = EXIT ]केवल सामान्य (गैर-सिग्नल किए गए) निकास पर कोड निष्पादित करने की अनुमति देता है। हालाँकि, सभी संकेतों के लिए जाल होता है जो अंतिम बार जाल को रीसेट करता है EXIT; normal_exit_only_cleanupयह भी संकेत है कि नहीं के लिए बुलाया जाएगा। इसके माध्यम से एक निकास द्वारा भी निष्पादित किया जाएगा set -e। यह ERR(जो डैश द्वारा समर्थित नहीं है) पर फंसने और [ $sig = ERR ]पहले एक चेक को जोड़कर तय किया जा सकता हैkill

सरलीकृत बैश-केवल संस्करण

दूसरी ओर, इस व्यवहार का अर्थ है कि बैश में आप बस कर सकते हैं

trap cleanup EXIT

बस कुछ सफाई कोड निष्पादित करने और निकास स्थिति को बनाए रखने के लिए।

संपादित

  • बैश के व्यवहार को "सब कुछ छोड़ दो"

  • निकालें KILL सिग्नल, जो फंस नहीं सकता है

  • संकेत नामों से SIG उपसर्ग निकालें

  • करने की कोशिश मत करो kill -s EXIT

  • set -eखाते में / ईआरआर लें


कोई सामान्य आवश्यकता नहीं है कि एक कार्यक्रम जो संकेतों को फंसाता है वह एक तरह से समाप्त हो जाता है जो इस तथ्य को संरक्षित करता है कि यह एक संकेत प्राप्त करता है। उदाहरण के लिए, एक कार्यक्रम यह घोषणा कर सकता है कि भेजना SIGINTइसे बंद करने का तरीका है और यह 0 के साथ बाहर निकलने का निर्णय ले सकता है अगर यह बिना किसी त्रुटि या किसी अन्य त्रुटि कोड को समाप्त करने में कामयाब रहा अगर यह सफाई से बंद नहीं हुआ। बिंदु में मामला: top। भागो top; echo $?और फिर Ctrl-C मारा। स्क्रीन पर डंप किया गया स्टेटस 0.
लुईस

1
उसे इंगित करने के लिए धन्यवाद। हालांकि, पोस्टर में विशेष रूप से निकास कोड रखने के बारे में पूछा गया था ।
philipp2100
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.