नियंत्रण जो प्रक्रिया Ctrl + C द्वारा रद्द हो जाती है


13

मेरे पास एक लाइव सीडी है जो लिनक्स में बूट करती है और एक छोटी बैश स्क्रिप्ट चलाती है। स्क्रिप्ट दूसरा प्रोग्राम खोजती है और चलाती है (जो आमतौर पर संकलित C ++ बाइनरी है)।

आप Ctrl+ दबाकर दूसरे कार्यक्रम को समाप्त करने में सक्षम होने वाले हैं C। ऐसा क्या होना चाहिए कि दूसरा प्रोग्राम रुक जाए और बैश स्क्रिप्ट क्लीनअप चलती रहे। वास्तव में क्या होता है कि मुख्य एप्लिकेशन और बैश स्क्रिप्ट दोनों समाप्त हो जाते हैं। जो एक समस्या है।

इसलिए मैंने trapबिल्ट का उपयोग बैश को SIGINT को नजरअंदाज करने के लिए कहा। और अब C ++ एप्लिकेशन को Ctrl+ Cसमाप्त करता है, लेकिन बैश अपना रन जारी रखता है। महान।

अरे हाँ ... कभी-कभी "दूसरी एप्लीकेशन" एक और बैश स्क्रिप्ट है। और उस मामले में, Ctrl+ Cअब कुछ भी नहीं करता है ।

जाहिर है कि यह कैसे काम करता है सामान की मेरी समझ गलत है ... मैं जो प्रक्रिया SIGINT जब उपयोगकर्ता प्रेस हो जाता है किस प्रकार नियंत्रित कर Ctrl+ C? मैं केवल एक विशिष्ट प्रक्रिया के लिए इस संकेत को निर्देशित करना चाहता हूं ।

जवाबों:


11

इंटरनेट के चेहरे की खोज के कई घंटों के बाद, मुझे जवाब मिल गया है।

  1. लिनक्स में एक प्रक्रिया समूह की धारणा है ।

  2. TTY ड्राइवर में फोरग्राउंड प्रोसेस ग्रुप की धारणा है।

  3. जब आप Ctrl+ दबाते हैं C, तो TTY फ़ोरग्राउंड प्रक्रिया समूह में हर प्रक्रियाSIGINT को भेजता है । ( यह ब्लॉग प्रविष्टि भी देखें ।)

यही कारण है कि संकलित बाइनरी और स्क्रिप्ट जो इसे लॉन्च करती है, दोनों क्लोएबर्ड हो जाती हैं। वास्तव में मैं केवल मुख्य आवेदन इस संकेत, प्राप्त करना चाहते हैं नहीं स्टार्टअप स्क्रिप्ट।

समाधान अब स्पष्ट है: हमें एप्लिकेशन को एक नई प्रक्रिया समूह में डालने की आवश्यकता है, और इसे इस TTY के लिए फोरग्राउंड प्रोसेस ग्रुप बनाना है। जाहिर है ऐसा करने की आज्ञा है

setsid -c <applcation>

इतना ही। अब जब उपयोगकर्ता Ctrl+ Cदबाएगा, तो SIGINT को आवेदन में भेजा जाएगा (और किसी भी बच्चे के पास) और कोई नहीं हो सकता। जो मुझे चाहिए था।

  • setsid अपने आप में एक नई प्रक्रिया समूह (वास्तव में, एक नया "सत्र", जो स्पष्ट रूप से प्रक्रिया समूहों का एक समूह है) में आवेदन डालता है।

  • -cध्वज जोड़ने से यह नया प्रक्रिया समूह वर्तमान TTY के लिए "अग्रभूमि" प्रक्रिया समूह बन जाता है। (यानी, यह SIGINTतब होता है जब आप Ctrl+ दबाते हैं C)

जब बैश करता है या किसी नई प्रक्रिया समूह में प्रक्रियाएँ नहीं चलाता है, तो मैंने बहुत सारी परस्पर विरोधी जानकारी देखी है। (विशेष रूप से, यह "संवादात्मक" और "गैर-संवादात्मक" गोले के लिए अलग-अलग प्रतीत होता है।) मैंने सुझाव दिए हैं कि आप इसे चतुर पाइप चालन के साथ काम करने के लिए प्राप्त कर सकते हैं ... मुझे नहीं पता। लेकिन ऊपर वाला दृष्टिकोण मेरे लिए काम करने लगता है।


5
आपको लगभग मिल गया ... स्क्रिप्ट चलाते समय डिफ़ॉल्ट रूप से नौकरी नियंत्रण अक्षम होता है, लेकिन आप इसे सक्षम कर सकते हैं set -msetsidजब आप बच्चे को चलाते हैं तो हर बार इस्तेमाल करने की तुलना में यह थोड़ा साफ और सरल होता है ।
Psusi

@psusi टिप के लिए धन्यवाद! मुझे केवल एक बच्चा चलाने की ज़रूरत है, इसलिए यह कोई बड़ी बात नहीं है। अब मैं जहां बैश मैनुअल यद्यपि में देखने के लिए पता है ...
MathematicalOrchid

विडंबना यह है कि मेरे पास उल्टा समस्या है जहां मैं चाहता हूं कि माता-पिता को शिगिंट को पकड़ना है, लेकिन यह "चतुर पाइप प्रवंचना" के कारण नहीं है। प्रगति समूह -> प्रक्रिया समूह
एंड्रयू डॉमासेक

2

जैसा कि मैंने f01 टिप्पणी में उल्लेख किया है, आपको चाइल्ड प्रोसेस को SIGTERM भेजना चाहिए। यहां कुछ स्क्रिप्ट हैं जो दिखाती हैं कि कैसे ^ C को फंसाना है और एक चाइल्ड प्रोसेस को सिग्नल भेजना है।

पहला, जनक।

traptest

#!/bin/bash

# trap test
# Written by PM 2Ring 2014.10.23

myname=$(basename "$0")
child=sleeploop

set_trap()
{
    sig=$1
    msg="echo -e \"\n$myname received ^C, sending $sig to $child, $pid\""
    trap "$msg; kill -s $sig $pid" SIGINT
}
trap "echo \"bye from $myname\"" EXIT

echo "running $child..."
./$child 5  &
pid=$!

# set_trap SIGINT
set_trap SIGTERM
echo "$child pid = $pid"

wait $pid
echo "$myname finished waiting"

और अब, बच्चा।

sleeploop

#!/bin/bash

# child script for traptest
# Written by PM 2Ring 2014.10.23

myname=$(basename "$0")
delay="$1"

set_trap()
{
    sig=$1
    trap "echo -e '\n$myname received $sig signal';exit 0" $sig
}

trap "echo \"bye from $myname\"" EXIT
set_trap SIGTERM
set_trap SIGINT

#Select sleep mode
if false
then
    echo "Using foreground sleep"
    Sleep()
    {
        sleep $delay
    }
else
    echo "Using background sleep"
    Sleep()
    {
        sleep "$delay" &
        wait $!
    }
fi

#Time to snooze :)
for ((i=0; i<5; i++));
do
    echo "$i: sleeping for $delay"
    Sleep
done

echo "$myname terminated normally"

यदि ट्रेपेस्ट SIGTERM चीजों को अच्छी तरह से भेजता है, लेकिन यदि ट्रेपेस्ट SIGINT भेजता है तो स्लीपलूप इसे कभी नहीं देखता है।

यदि स्लीप्लोप जाल SIGTERM, और स्लीप मोड अग्रभूमि है, तो यह सिग्नल का जवाब नहीं दे सकता जब तक कि यह वर्तमान नींद से नहीं उठता। लेकिन अगर स्लीप मोड बैकग्राउंड है, तो यह तुरंत प्रतिक्रिया देगा।


इस महान उदाहरण के लिए धन्यवाद, इसने मुझे यह समझने में बहुत मदद की कि मैं अपनी स्क्रिप्ट कैसे सुधार सकता हूं :)
TabeaKischka

2

आपकी दीक्षा बैश स्क्रिप्ट में।

  • दूसरे कार्यक्रम के पीआईडी ​​का ध्यान रखें

  • SIGINT को पकड़ें

  • जब आपने एक SIGINT को पकड़ा है, तो दूसरे प्रोग्राम PID को एक SIGINT भेजें


1
यह मदद नहीं कर सकता है। यदि आप SIGINT को पैरेंट स्क्रिप्ट में फँसाते हैं तो चाइल्ड स्क्रिप्ट SIGINT को प्राप्त नहीं कर पाएगी, चाहे आप इसे माता-पिता से भेजें या किसी अन्य शेल से। लेकिन यह उतना बुरा नहीं है जितना यह लगता है, क्योंकि आप बच्चे को सिग्मर भेज सकते हैं, जो जाहिर है, वैसे भी उपयोग करने के लिए पसंदीदा संकेत है।
बजे PM 2Ring

1
SIGTERM "पसंदीदा" क्यों है?
MathematicalOrchid

वे लगभग समान हैं। SIGINT कंट्रोलिंग टर्मिनल / यूजर जैसे Ctrl + C द्वारा भेजा गया सिग्नल है। अगर आप प्रक्रिया को समाप्त करना चाहते हैं तो SIGTERM आप भी भेज सकते हैं। यहाँ अधिक विचार en.wikipedia.org/wiki/Unix_signal
f01
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.