2014-07-18 5 views
6

अंतिम लक्ष्य: बैश स्क्रिप्ट जो पृष्ठभूमि नौकरियों को समाप्त करने की प्रतीक्षा कर रहा है, पहले Ctrl-c पर निरस्त नहीं है; इसके बजाय, इसे छोड़ने के लिए इसे दूसरे Ctrl-c की आवश्यकता होती है।बैश: स्क्रिप्ट से बाहर निकलने के लिए डबल Ctrl-c की आवश्यकता हो सकती है?

मुझे अच्छी तरह से पता है कि कैसे BASH-buildin trap काम करता है। आप या तो:

  1. एक संकेत पूरी तरह अनदेखी करने के लिए इसका इस्तेमाल (जैसे, trap '' 2) ... या

  2. का प्रयोग करें यह एक संकेत मूल कार्य होने की अनुमति दी है इससे पहले निष्पादित मनमाना आदेशों के लिए (जैसे , trap cmd 2, जहां cmd माता पिता स्क्रिप्ट से पहले चलाया जाता है SIGINT के कारण बाधित हो जाएगा)

तो सवाल यह करने पर निर्भर करता:

012,351,

मैं कैसे प्रभावी ढंग से & 2 एक साथ गठजोड़ कर सकते हैं, यानी, को रोकने के अंत परिणाम एक संकेत करने के लिए नेतृत्व करेंगे (- जैसे, कारण SIGINT रद्द स्क्रिप्ट बंद) करते हुए भी कि बनाने संकेत कुछ और कारण (- उदाहरण के लिए, काउंटर में वृद्धि, काउंटर की जांच करें और सशर्त रूप से या तो चेतावनी या बाहर निकलें)।

अधिक बस रखो:

मैं एक संकेत कैसे कर सकते हैं कोई अन्य विषय कुछ करना; इससे पहले कि यह अपनी बात करता है, नौकरी न डालें।

यहां कुछ उदाहरण कोड दिखाया गया है जो मैं लक्षित कर रहा हूं; हालांकि, यह निश्चित रूप से काम नहीं करता है - क्योंकि trap केवल या ऊपर से ही कर सकता है।

#!/bin/bash 
declare -i number_of_times_trap_triggered 
cleanup_bg_jobs() { 
    number_of_times_trap_triggered+=1 
    if [[ ${number_of_times_trap_triggered} -eq 1 ]]; then 
     echo "There are background jobs still running" 
     echo "Hit Ctrl-c again to cancel all bg jobs & quit" 
    else 
     echo "Aborting background jobs" 
     for pid in ${bg_jobs}; do echo " Killing ${pid}"; kill -9 ${pid}; done 
    fi 
} 
f() { sleep 5m; } 
trap cleanup_bg_jobs 2 
bg_jobs= 
for job in 1 2 3; do 
    f & 
    bg_jobs+=" $!" 
done 
wait 

तो यह उत्पादन आप अंत हो रही है जब आप Ctrl-c एक बार प्रेस है।

[rsaw:~]$ ./zax 
^CThere are background jobs still running 
Hit Ctrl-c again to cancel all bg jobs & quit 
[rsaw:~]$ ps axf|tail -6 
24569 pts/3 S  0:00 /bin/bash ./zax 
24572 pts/3 S  0:00 \_ sleep 5m 
24570 pts/3 S  0:00 /bin/bash ./zax 
24573 pts/3 S  0:00 \_ sleep 5m 
24571 pts/3 S  0:00 /bin/bash ./zax 
24574 pts/3 S  0:00 \_ sleep 5m 

बेशक मैं पहली बार Ctrl-c पर नौकरियों को साफ करने को संशोधित कर सकता है, लेकिन यह है कि नहीं है कि मैं क्या चाहता हूँ। मैं पहले ट्रैप ट्रिगर होने के बाद बाश को छोड़ने से रोकना चाहता हूं ... जब तक कि यह दूसरी बार ट्रिगर न हो जाए।

पुनश्च: लक्ष्य मंच लिनक्स है (मैं POSIX अनुपालन के बारे में कम परवाह नहीं कर सकता है) मार v4 वाले +

उत्तर

1

एक सहयोगी (ग्रेगा) ने मुझे एक समाधान दिया जो ... अच्छा मैं विश्वास नहीं कर सकता कि मैंने पहले इसके बारे में नहीं सोचा था।

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

रिकॉर्ड के लिए, wait यहां काम नहीं करेगा। (रिकर्सिव।) हालांकि, मेरे मूल कोड के cleanup_bg_jobs() फ़ंक्शन पर sleep कमांड जोड़ने से इसका ख्याल रखेगा .. लेकिन अनाथ प्रक्रियाओं का कारण बन जाएगा। इसलिए मैंने यह सुनिश्चित करने के लिए प्रक्रिया समूहों का अधिग्रहण किया कि लिपि के सभी बच्चे वास्तव में मारे जाएंगे। भावी पीढ़ी के लिए सरलीकृत उदाहरण:

#!/bin/bash 
declare -i count= 
handle_interrupt() { 
    count+=1 
    if [[ ${count} -eq 1 ]]; then 
     echo "Background jobs still running" 
     echo "Hit Ctrl-c again to cancel all bg jobs & quit" 
     sleep 1h 
    else 
     echo "Aborting background jobs" 
     pkill --pgroup 0 
    fi 
} 
f() { tload &>/dev/null; } 
trap handle_interrupt 2 
for job in 1 2 3; do 
    f & 
done 
wait 
4

मैं इस here की तरह कुछ किया है और यह ज्यादातर यह करने के लिए टूट जाती है:

ATTEMPT=0 
handle_close() { 
    if [ $ATTEMPT -eq 0 ]; then 
     ATTEMPT=1 
     echo "Shutdown." 
    else 
     echo "Already tried to shutdown. Killing." 
     exit 0 
    fi 
} 
trap handle_close SIGINT SIGTERM 

आप अपने हैंडलर में एक चर सेट कर सकते हैं कि अगली बार जब यह फंस जाए तो आप फिर से जांच सकते हैं।

+0

आमतौर पर इस मामले में, दो Ctrl + C को प्रोग्राम को रोकने के लिए निरंतर होना आवश्यक है। इसलिए, जब एक कुंजी डाउन कैप्चर की जाती है तो एक बेहतर समाधान को ATTEMP को 0 पर सेट करना चाहिए। –

+0

वैली की कोशिश करने के लिए धन्यवाद, लेकिन आप जो पेशकश कर रहे हैं वह वास्तव में जो मैंने पूछा है उसका जवाब नहीं देता है। पहले 'echo Shutdown.' कमांड चलाने के बाद यह बंद हो जाएगा। – rsaw

+0

पीएस: मैंने अपनी पोस्ट को अपने कुछ उदाहरण कोड के साथ अपडेट किया ताकि यह दिखाया जा सके कि 'जाल' काम नहीं करता है कि आप कैसे सोचते हैं कि यह काम करता है। (जब तक मैं पागल नहीं हूं।) – rsaw

3

मैं एक अलग उपयोग के मामले था, और, यहाँ समाधान को छोड़ना चाहते हैं के रूप में गूगल मुझे इस विषय का नेतृत्व किया। आप एक आदेश चलाकर रख सकते हैं, और उपयोगकर्ता एक CTRL+C साथ उसे पुन: प्रारंभ करने की अनुमति है, और निम्नलिखित तरीके से डबल CTRL+C के साथ मारने:

trap_ctrlC() { 
    echo "Press CTRL-C again to kill. Restarting in 2 second" 
    sleep 2 || exit 1 
} 

trap trap_ctrlC SIGINT SIGTERM 

while true; do 
    ... your stuff here ... 
done 
+0

यह सुंदर है। टी.के.एस – cleison

0
  1. लिए इसका उपयोग करें एक संकेत मूल कार्य से पहले मार डाला मनमाना आदेशों है तो होना ही अनुमति दी है

डिजिटल (जैसे, जाल cmd 2, जहां cmd ​​माता पिता स्क्रिप्ट से पहले चलाया जाता है SIGINT के कारण बाधित हो जाएगा) उपर्युक्त का टुकड़ा हिस्सा गलत है। एक जाल हैंडलर के बजाय SIGINT (या जो कुछ भी) प्रक्रिया को बाधित करने के बजाए चलाया जाता है। अधिक सही:

  • SIGINT (और सबसे की, लेकिन सभी नहीं, अन्य संकेतों) का डिफ़ॉल्ट क्रिया प्रक्रिया
  • trap "command" SIGINT कारणों command ( के साथ ही नहीं ) के बजाय चलाने के लिए समाप्त करने के लिए है डिफ़ॉल्ट कार्रवाई

तो आपके SIGINT हैंडलर को स्थापित करने के साथ, SIGINT पूरी स्क्रिप्ट को बाधित नहीं करता है। लेकिन यह wait कमांड को बाधित करता है। जब जाल हैंडलर खत्म होता है, तो स्क्रिप्ट wait के बाद फिर से शुरू होती है, यानी यह अंत से गिर जाती है और सामान्य रूप से निकलती है। आप कुछ डिबगिंग कोड जोड़कर इस देख सकते हैं:

echo Waiting 
wait 
echo Back from wait 
exit 55     # Arbitrary value that wouldn't otherwise occur 

इस संस्करण का उत्पादन निम्नलिखित:

$ foo 
Waiting 
^CThere are background jobs still running 
Hit Ctrl-c again to cancel all bg jobs & quit 
back from wait 
$ echo $? 
55 
$ 

आपको क्या करने की जरूरत है हैंडलर रिटर्न के बाद wait दोहराने है।इस संस्करण में:

#!/bin/bash 
declare -i number_of_times_trap_triggered 
cleanup_bg_jobs() { 
    number_of_times_trap_triggered+=1 
    if [[ ${number_of_times_trap_triggered} -eq 1 ]]; then 
     echo "There are background jobs still running" 
     echo "Hit Ctrl-c again to cancel all bg jobs & quit" 
    else 
     echo "Aborting background jobs" 
     for pid in ${bg_jobs}; do echo " Killing ${pid}"; kill -9 ${pid}; done 
     exit 1 
    fi 
} 
f() { sleep 5m; } 
trap cleanup_bg_jobs 2 
bg_jobs= 
for job in 1 2 3; do 
    f & 
    bg_jobs+=" $!" 
done 

while [ 1 ]; do 
    echo Waiting 
    wait 
    echo Back from wait 
done 

के रूप में आप का अनुरोध किया है:

$ ./foo 
Waiting 
^CThere are background jobs still running 
Hit Ctrl-c again to cancel all bg jobs & quit 
Back from wait 
Waiting 
^CAborting background jobs 
    Killing 24154 
    Killing 24155 
    Killing 24156 
$ 

नोट्स:

  • मैं डिबगिंग सामान में छोड़ दिया है; जाहिर है आप इसे उत्पादन में हटा देंगे
  • हैंडलर अब उपप्रोसेस को मारने के बाद exit 1 करता है। असीमित मुख्य लूप
संबंधित मुद्दे