2013-08-28 4 views
11

script1.sh:बैश: जब बच्चे स्क्रिप्ट SIGINT जाल करता है तो मूल स्क्रिप्ट SIGINT पर क्यों समाप्त नहीं होती है?

#!/bin/bash  

./script2.sh 
echo after-script 

script2.sh:

#!/bin/bash 

function handler { 
    exit 130 
} 

trap handler SIGINT 

while true; do true; done 

जब मैं एक टर्मिनल से script1.sh शुरू, और फिर अपनी प्रक्रिया समूह के लिए SIGINT भेजने के लिए Ctrl + C का उपयोग करें, संकेत script2.sh द्वारा फंस गया है और जब script2.sh समाप्त हो जाता है, script1.sh प्रिंट करता है "बाद-स्क्रिप्ट"। हालांकि, मैं script2.sh को आमंत्रित करने वाली लाइन के बाद तुरंत समाप्त होने के लिए script1.sh की अपेक्षा करता। इस उदाहरण में यह मामला क्यों नहीं है?

अतिरिक्त टिप्पणी (संपादित करें):

  • script1.sh और script2.sh के रूप में एक ही प्रक्रिया समूह में हैं, SIGINT दोनों लिपियों के लिए भेजा जाता है जब Ctrl + C कमांड लाइन पर दबाया जाता है । यही कारण है कि मैं script1.sh को जारी रखने की उम्मीद नहीं करता जब script2.sh बाहर निकलता है।

  • जब लाइन "जाल हैंडलर SIGINT" script2.sh में बाहर टिप्पणी की है, script1.sh बाहर निकलने के तुरंत बाद script2.sh मौजूद है। मैं जानना चाहता हूं कि यह अलग-अलग क्यों व्यवहार करता है, क्योंकि script2.sh केवल उसी निकास कोड (130) उत्पन्न करता है।

+1

शायद 'set -e' का उपयोग करें? – phs

उत्तर

10

न्यू जवाब:

यह सवाल कहीं अधिक दिलचस्प तुलना में मैं मूल रूप से संदिग्ध है। इस सवाल का जवाब अनिवार्य रूप से यहां दी गई है:

What happens to a SIGINT (^C) when sent to a perl script containing children?

यहाँ प्रासंगिक tidbit है। मुझे एहसास है कि आप पर्ल का उपयोग नहीं कर रहे हैं, लेकिन मुझे लगता है कि बैश सी के सम्मेलन का उपयोग कर रहा है।

पर्ल के अंतर्निहित प्रणाली समारोह सिर्फ सी प्रणाली मानक सी पुस्तकालय से (3) समारोह की तरह जहाँ तक संकेत चिंतित हैं काम करता है। यदि आप पर्ल के सिस्टम() या पाइप ओपन या बैकटिक्स के संस्करण का उपयोग कर रहे हैं, तो माता-पिता - द्वारा कॉल किए गए एक के बजाय एक कॉलिंग सिस्टम - यदि कोई भी 0,चल रहा है, तो IGNORE किसी भी सिगिनट और सिगक्विट होगा।

This explanation सबसे अच्छा विकल्प है जिसे मैंने बनाया जा सकता है। यह भी कहता है कि बैश डब्लूसीई दृष्टिकोण करता है। यही है, जब एक अभिभावक प्रक्रिया SIGINT प्राप्त करती है, तो यह तब तक प्रतीक्षा करती है जब तक कि उसके बच्चे की प्रक्रिया वापस न हो जाए। यदि उस प्रक्रिया को एक सिगिनट से बाहर निकाला जाता है, तो यह सिगिनट से भी निकलता है। अगर बच्चा किसी अन्य तरीके से निकलता है तो यह सिगिनट को अनदेखा करता है।

भी एक तरीका बुला खोल बता सकता है कि कहा जाता है कार्यक्रम SIGINT पर चले जाते हैं नहीं है और अगर यह SIGINT पर ध्यान नहीं दिया (या अन्य प्रयोजनों के लिए प्रयोग किया जाता है)। WUE रास्ते के रूप में, खोल बच्चे के लिए पूर्ण करने की प्रतीक्षा करता है। यह आंकड़े बताता है कि कार्यक्रम SIGINT पर समाप्त हुआ था और यदि तो, यह स्क्रिप्ट को बंद कर देता है। यदि कार्यक्रम ने कोई अन्य निकास किया है, तो स्क्रिप्ट जारी रहेगी। मैं इस दस्तावेज़ के बाकी हिस्सों के लिए "डब्लूसीई" ("प्रतीक्षा और सहकारी निकास" के लिए) करने का तरीका कहूंगा।

मुझे बैश मैन पेज में इसका कोई संदर्भ नहीं मिल रहा है, लेकिन मैं जानकारी दस्तावेज़ों को देख रहा हूं। लेकिन मुझे 99% विश्वास है कि यह सही जवाब है।

पुराना जवाब:

एक बैश लिपि में एक आदेश से एक अशून्य बाहर निकलें स्थिति कार्यक्रम समाप्त नहीं करता। यदि आप echo $?./script2.sh के बाद 130 दिखाएंगे तो आप set -e का उपयोग करके स्क्रिप्ट को समाप्त कर सकते हैं क्योंकि phs सुझाव देता है।

$ help set 
... 
-e Exit immediately if a command exits with a non-zero status. 
+0

यह सवाल का काफी जवाब नहीं देता है। ध्यान दें कि SIGINT को script1.sh और script2.sh दोनों को भेजा जाता है जब टर्मिनल पर Ctrl + C दबाया जाता है। मैंने प्रश्न में कुछ अतिरिक्त टिप्पणी जोड़े हैं। –

+0

यह बहुत दिलचस्प है। मैं अभी भी "जाल हैंडलर सिगिनट" के साथ और बिना संस्करणों के बीच के अंतर के बारे में सोच रहा हूं। मुझे संदेह है कि संकेत पहली बार बच्चे को और फिर माता-पिता को दिया जाता है। जब बच्चे में एक जाल हैंडलर स्थापित किया जाता है, तो शायद इसे समाप्त करने में थोड़ा समय लगता है, और इस प्रकार यह तब भी जिंदा है जब माता-पिता को सिग्नल प्राप्त होता है (जो इसे अनदेखा करता है)। एक हैंडलर के बिना, जब बच्चे को सिग्नल प्राप्त होता है तो बच्चा शायद ही समाप्त हो चुका है, इस प्रकार _not_ इसे अनदेखा कर रहा है और समाप्त कर रहा है। क्या कोई मेरे अनुमानों की पुष्टि कर सकता है? –

+0

आपका अनुमान सही नहीं है। मैंने अपना जवाब अपडेट कर लिया है। – seanmcl

0

कारण अपने script1.sh समाप्त नहीं करता है कि script2.sh एक subshell में चल रहा है है। पूर्व स्क्रिप्ट से बाहर निकलें करने के लिए, आप या तो -e सेट के रूप में PHS और seanmcl ने सुझाव दिया या कह कर ही खोल में चलाने के लिए script2.sh मजबूर कर सकते हैं: अपने पहले स्क्रिप्ट में

. ./script2.sh 

। यदि आप अपनी स्क्रिप्ट निष्पादित करने से पहले set -x करना चाहते हैं तो आप जो देख रहे हैं वह स्पष्ट होगा। help set बताता है:

-x Print commands and their arguments as they are executed. 
0

(SIGINT भेजने आपको अपने दूसरे स्क्रिप्ट के रूप में अच्छी तरह से SIGHUP, या SIGQUIT जैसे अन्य सुरक्षित और प्रयोग करने योग्य संकेतों द्वारा अपनी मूल स्क्रिप्ट, जिसमें माता-पिता स्क्रिप्ट विचार कर सकते हैं या जाल पर एक समाप्त संकेत भेजने के लिए दे सकते हैं काम नहीं करता है)।

script1.sh:

#!/bin/bash 

trap 'exit 0' SIQUIT ## We could also just accept SIGHUP if we like without traps but that sends a message to the screen. 

./script2.sh ## or "bash script.sh" or "(. ./script.sh;) which would run it on another process 
echo after-script 

script2.sh:

#!/bin/bash 

SLEEPPID='' 

PID=$BASHPID 
read PPID_ < <(exec ps -p "$PID" -o "$ppid=") 

function handler { 
    [[ -n $SLEEPPID ]] && kill -s SIGTERM "$SLEEPPID" &>/dev/null 
    kill -s SIGQUIT "$PPID_" 
    exit 130 
} 

trap handler SIGINT 

# better do some sleeping: 

for ((;;)); do 
    [[ -n $SLEEPPID ]] && kill -s 0 "$SLEEPPID" &>/dev/null || { 
    sleep 20 & 
    SLEEPPID=$! 
    } 
    wait 
done 

अपने script1.sh में आपका मूल अंतिम पंक्ति सिर्फ इस तरह हो सकता है और साथ ही अपनी स्क्रिप्ट का इरादा क्रियान्वयन के आधार पर।

./script2.sh || exit 
... 

या

./script2.sh 
[[ $? -eq 130 ]] && exit 
... 
1

@ seanmcl के दूसरे भाग में अपडेट होता है जवाब सही है और http://www.cons.org/cracauer/sigint.html के लिए लिंक ध्यान से के माध्यम से पढ़ने के लिए एक बहुत अच्छी है।

उस लिंक से, "आप एक विशेष संख्यात्मक मूल्य के साथ बाहर निकलने (3) द्वारा उचित निकास स्थिति को 'नकली' नहीं कर सकते हैं, भले ही आप अपने सिस्टम" के लिए संख्यात्मक मान देखें। असल में, यही है कि @ हरमन स्पीच की script2.sh में क्या प्रयास किया जा रहा है।

function handler { 
    # ... do stuff ... 
    trap INT 
    kill -2 $$ 
} 

यह प्रभावी रूप से संकेत हैंडलर और "rethrows" SIGINT, बैश प्रक्रिया ऐसी है कि उचित झंडे के साथ बाहर निकलने के लिए पैदा कर रहा निकालता है:

एक जवाब script2.sh में समारोह हैंडलर संशोधित करने के लिए इस प्रकार है इसके माता-पिता की बैश प्रक्रिया तब सिगिनट को सही तरीके से संभालती है जिसे मूल रूप से भेजा गया था। इस तरह, set -e या किसी अन्य हैक का उपयोग वास्तव में आवश्यक नहीं है।

यह भी ध्यान देने योग्य है कि यदि आपके पास एक निष्पादन योग्य है जो SIGINT भेजे जाने पर गलत तरीके से व्यवहार करता है (यह उपर्युक्त लिंक में "उचित कार्यक्रम कैसे बनें" के अनुरूप नहीं है, उदा।यह एक सामान्य रिटर्न-कोड से निकलता है), इस प्रक्रिया को कॉल करने का एक तरीका निम्न प्रकार की एक स्क्रिप्ट के साथ कॉल को लपेटना है:

#!/bin/bash 

function handler { 
    trap INT 
    kill -2 $$ 
} 

trap handler INT 
badprocess "[email protected]" 
संबंधित मुद्दे