2013-02-04 13 views
7

क्या कोई सबप्रोसेस का आह्वान करने का कोई तरीका है ताकि यह और उसके सभी वंशजों को एक बाधा भेजी जा सके, जैसे कि आप Ctrl-C अग्रभूमि कार्य करते हैं? मैं एक लॉन्चर स्क्रिप्ट को मारने की कोशिश कर रहा हूं जो लंबे समय से चलने वाले बच्चे को आमंत्रित करता है। मैंने kill -SIGINT $child (जो इसके वंशजों को बाधा नहीं भेजता है, इसलिए नो-ऑप है) और kill -SIGINT -$child (जो काम करता है जब इंटरैक्टिव रूप से बुलाया जाता है लेकिन स्क्रिप्ट में नहीं चल रहा है)।बैश स्क्रिप्ट एक पृष्ठभूमि कार्य में Ctrl-C के बराबर कैसे कर सकता है?

यहां एक टेस्ट स्क्रिप्ट है। लंबी चल रही स्क्रिप्ट test.sh --child है। जब आप test.sh --parent पर कॉल करते हैं, तो यह test.sh --child & को आमंत्रित करता है और फिर इसे मारने का प्रयास करता है। मैं माता-पिता को सफलतापूर्वक बच्चे को कैसे मार सकता हूं?

#!/bin/bash 

if [ "$1" = "--child" ]; then 
sleep 1000 

elif [ "$1" = "--parent" ]; then 
"$0" --child & 
for child in $(jobs -p); do 
    echo kill -SIGINT "-$child" && kill -SIGINT "-$child" 
done 
wait $(jobs -p) 

else 
echo "Must be invoked with --child or --parent." 
fi 

मुझे पता है तुम, trap संकेतों को लंबे समय से चल बच्चे को संशोधित कर सकते हैं कि उन्हें अपने उपप्रक्रिया को भेजें, और उसके बाद ( Bash script kill background (grand)children on Ctrl+C से) इंतजार है, लेकिन वहाँ बच्चे स्क्रिप्ट को संशोधित किए बिना किसी भी तरह से है?

उत्तर

4

इस पढ़ें: How to send a signal SIGINT from script to script ? BASH

इसके अलावा से info bash

To facilitate the implementation of the user interface to job control, 
    the operating system maintains the notion of a current terminal process 
    group ID. Members of this process group (processes whose process group 
    ID is equal to the current terminal process group ID) receive keyboard- 
    generated signals such as SIGINT. These processes are said to be in 
    the foreground. Background processes are those whose process group ID 
    differs from the terminal's; such processes are immune to keyboard-gen‐ 
    erated signals. 

तो bashप्रक्रिया समूह आईडी द्वारा अग्रभूमि प्रक्रियाओं से पृष्ठभूमि प्रक्रियाओं अलग करती है। यदि प्रक्रिया समूह आईडीप्रक्रिया आईडी के बराबर है, तो प्रक्रिया एक अग्रभूमि प्रक्रिया है, और इसे SIGINT सिग्नल प्राप्त होने पर समाप्त कर दिया जाएगा। अन्यथा यह समाप्त नहीं होगा (जब तक यह फंस नहीं जाता)।

आप जब आप एक पृष्ठभूमि प्रक्रिया (& के साथ) एक स्क्रिप्ट के भीतर से चलाने के लिए,

ps x -o "%p %r %y %x %c " 

इस प्रकार के साथ प्रक्रिया समूह क्रमांक देख सकते हैं, यह SIGINT संकेत की अनदेखी जब तक यह फंस गया है जाएगा।

हालांकि, आप अभी भी SIGKILL, SIGTERM आदि जैसे अन्य सिग्नल के साथ बाल प्रक्रिया को मार सकते हैं।

उदाहरण के लिए

, अगर आप को अपनी स्क्रिप्ट को बदलने यह निम्नलिखित सफलतापूर्वक बच्चे प्रक्रिया मार डालेगा:

#!/bin/bash 

if [ "$1" = "--child" ]; then 
    sleep 1000 
elif [ "$1" = "--parent" ]; then 
    "$0" --child & 
    for child in $(jobs -p); do 
    echo kill "$child" && kill "$child" 
    done 
    wait $(jobs -p) 

    else 
    echo "Must be invoked with --child or --parent." 
fi 

आउटपुट:

$ ./test.sh --parent 
kill 2187 
./test.sh: line 10: 2187 Terminated    "$0" --child 
+0

अद्यतन उत्तर। – user000001

5
somecommand & 

$!

somecommand & 
pid[0]=$! 
anothercommand & 
pid[1]=$! 
trap INT " kill ${pid[0]} ${pid[1]}; exit 1" 
wait 

में बच्चे का एक पीआईडी ​​रिटर्न मैं इस मॉडल के साथ के बजाय बैश काम पर नियंत्रण (bg, FG, रोजगार) के साथ शुरू होगा। आम तौर पर विरासत विरासत और अनाथ प्रक्रियाओं का उपयोग करता है। आप कौनसी समस्याएं हल करने की कोशिश कर रहे हैं?

+0

मुझे एहसास है कि मैं बाल स्क्रिप्ट को संशोधित करने के लिए बाधाओं को पारित करने के लिए संशोधित कर सकता हूं। मैं बस सोच रहा था कि बाल लिपि को संशोधित किए बिना वंशजों को बाधा भेजना संभव है या नहीं। – yonran

+1

एफवाईआई: लाइन 2 में $ होना चाहिए! $ 1 – Tully

+0

INT मेरे लिए काम नहीं करता है, मैंने ओएस एक्स – Michal

8

किसी को भी सोच के लिए, यह कैसे आप में बच्चे का शुभारंभ है पृष्ठभूमि और उन्हें ctrl + c:

#!/usr/bin/env bash 
command1 & 
pid[0]=$! 
command2 & 
pid[1]=$! 
trap "kill ${pid[0]} ${pid[1]}; exit 1" INT 
wait 
+0

यह उपयोगी है, हालांकि मुझे पता चला कि 'मार' केवल तर्कों में निर्दिष्ट प्रक्रियाओं को मार देगा, न कि उनके वंशज। – Flimm

0

आपका उपयोग जारी रख सकते हैंपृष्ठभूमि कार्यों के साथ एक आसान छोटी मोड़ के साथ: अपने एसिंक्रोनस सबप्रोसेस कॉल को किसी फ़ंक्शन या {} पर रखें, और इसे setsid दें ताकि इसका अपना प्रोसेस ग्रुप हो। का उपयोग करते हुए और SIGINT प्रचार और एक अन्य संकेत

  • से केवल फोन करने को संशोधित करने का उपयोग नहीं कर

    • : "$0" --child & को { setsid "$0" --child; } &

    • जोड़ने

      यहाँ अपनी स्क्रिप्ट यह है रखना है पूरे पहला इरादा आपके बच्चे के उदाहरण के पीआईडी ​​प्राप्त करने के लिए आवश्यक कोड, जो पृष्ठभूमि सबहेल में एकमात्र प्रक्रिया है।

      #!/bin/bash 
      
      if [ "$1" = "--child" ]; then 
      sleep 1000 
      
      elif [ "$1" = "--parent" ]; then 
      { setsid "$0" --child; } & 
      subshell_pid=$! 
      pids=$(ps -ax -o ppid,pid --no-headers | 
          sed -r 's/^ +//g;s/ +/ /g' | 
          grep "^$subshell_pid " | cut -f 2 -d " "); 
      for child in $pids; do 
          echo kill -SIGINT "-$child" && kill -SIGINT "-$child" 
      done 
      wait $subshell_pid 
      
      else 
      echo "Must be invoked with --child or --parent." 
      

      यहाँ बैश मैनुअल

      पृष्ठभूमि प्रक्रिया पर प्रक्रिया समूह आईडी प्रभाव (में नौकरी नियंत्रण दस्तावेज़ के अनुभाग) से महत्वपूर्ण दस्तावेज़ हिस्सा है:

    अपने कोड है:

    [...] प्रक्रियाओं डब्ल्यू नली प्रक्रिया समूह आईडी वर्तमान टर्मिनल प्रक्रिया समूह आईडी के बराबर है [..] SIGINT जैसे कीबोर्ड-जेनरेट किए गए सिग्नल प्राप्त करें। इन प्रक्रियाओं को अग्रभूमि में कहा जाता है। पृष्ठभूमि प्रक्रिया वे हैं जिनकी प्रक्रिया समूह आईडी टर्मिनल के से अलग है; ऐसी प्रक्रिया कुंजीपटल से उत्पन्न सिग्नल से प्रतिरक्षा हैं।

    डिफ़ॉल्ट हैंडलर SIGINT और SIGQUIT (में सिग्नल दस्तावेज़ के खंड) के लिए:

    गैर builtin बैश द्वारा चलाए जा रहे आदेशों संकेत संचालकों मूल्यों के पैरेंट से खोल द्वारा विरासत में मिली लिए निर्धारित किया है। जब नौकरी नियंत्रण प्रभावी नहीं होता है, तो असीमित कमांडर्स इन विरासत वाले हैंडलरों के अलावा SIGINT और SIGQUIT को अनदेखा करते हैं।

    और जाल के संशोधन के बारे में (में trap builtin doc):

    सिग्नल खोल करने के लिए प्रवेश पर ध्यान नहीं दिया ट्रैप नहीं किया जा सकता है या रीसेट