शेल = ट्रू के साथ लॉन्च किए गए अजगर उपप्रकार को कैसे समाप्त करें


308

मैं निम्नलिखित कमांड के साथ एक उपप्रकार ला रहा हूं:

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

हालांकि, जब मैं का उपयोग कर मारने की कोशिश:

p.terminate()

या

p.kill()

आदेश पृष्ठभूमि में चलता रहता है, इसलिए मैं सोच रहा था कि मैं वास्तव में इस प्रक्रिया को कैसे समाप्त कर सकता हूं।

ध्यान दें कि जब मैं कमांड चलाता हूं:

p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)

यह जारी करते समय सफलतापूर्वक समाप्त होता है p.terminate()


आपका cmdलुक कैसा है? इसमें एक कमांड हो सकती है जो शुरू होने वाली कई प्रक्रियाओं को ट्रिगर करती है। इसलिए यह स्पष्ट नहीं है कि आप किस प्रक्रिया के बारे में बात करते हैं।
बजे रॉबर्ट सिएमर


1
shell=Trueबड़ा फर्क नहीं पड़ता?
चार्ली पार्कर

जवाबों:


410

एक प्रक्रिया समूह का उपयोग करें ताकि समूहों में सभी प्रक्रिया को संकेत भेजने में सक्षम किया जा सके। उसके लिए, आपको स्पॉन्स्ड / चाइल्ड प्रोसेस की मूल प्रक्रिया के लिए एक सेशन आईडी संलग्न करना चाहिए , जो आपके मामले में एक शेल है। यह इसे प्रक्रियाओं का समूह नेता बनाएगा। तो अब, जब एक संकेत प्रक्रिया समूह के नेता को भेजा जाता है, तो यह इस समूह की सभी बाल प्रक्रियाओं में प्रसारित हो जाता है।

यहाँ कोड है:

import os
import signal
import subprocess

# The os.setsid() is passed in the argument preexec_fn so
# it's run after the fork() and before  exec() to run the shell.
pro = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                       shell=True, preexec_fn=os.setsid) 

os.killpg(os.getpgid(pro.pid), signal.SIGTERM)  # Send the signal to all the process groups

2
@PiotrDobrogost: अफसोस की बात है, क्योंकि os.setsidविंडोज़ में उपलब्ध नहीं है ( docs.python.org/library/os.html#os.setsid ), मुझे नहीं पता कि यह मदद कर सकता है लेकिन आप यहां देख सकते हैं ( bugs.python.org) / जारी करने के लिए कैसे के बारे में कुछ अंतर्दृष्टि के लिए)।
मौड

6
इससे कैसे subprocess.CREATE_NEW_PROCESS_GROUPसंबंधित है?
पिओट्र डोब्रोगोस्ट

11
हमारे परीक्षण शर्करा कि सेटसाइड! = सेटएस्पिड, और उस os.pgkill केवल उपप्रकार मारता है कि अभी भी एक ही प्रक्रिया समूह आईडी है। प्रक्रिया समूह जो बदल गए हैं, वे नहीं मारे गए हैं, भले ही वे अभी भी एक ही सत्र आईडी हो ...
hwjp


4
मैं os.setsid () करने की सलाह नहीं दूंगा, क्योंकि इसके दूसरे प्रभाव भी हैं। दूसरों के बीच, यह कंट्रोलिंग TTY को डिस्कनेक्ट करता है और नई प्रक्रिया को प्रोसेस ग्रुप लीडर बनाता है। Win.tue.nl/~aeb/linux/lk/lk-10.html
परसेंटेज

92
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
p.kill()

p.kill() खोल प्रक्रिया को मारने और cmd अभी भी चल रहा है।

मुझे इससे एक सुविधाजनक फ़िक्स मिला:

p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)

यह cmd को शेल प्रक्रिया को इनहेरिट करने का कारण बनेगा, बजाय इसके कि शेल लॉन्च एक चाइल्ड प्रोसेस है, जो कि मारा नहीं जाता है। p.pidतब आपके cmd प्रोसेस की id होगी।

p.kill() कार्य करना चाहिए।

मुझे नहीं पता कि आपके पाइप पर इसका क्या प्रभाव पड़ेगा।


1
* निक्स के लिए अच्छा और हल्का समाधान, धन्यवाद! लिनक्स पर काम करता है, मैक के लिए भी काम करना चाहिए।
मार्सॉफ्ट

बहुत अच्छा समाधान है। यदि आपका cmd किसी अन्य चीज़ के लिए एक शेल स्क्रिप्ट आवरण है, तो अंतिम बाइनरी को केवल एक उपप्रकार होने के लिए निष्पादन के साथ कॉल करें।
निकोलिनक्स 17

1
ये सुन्दर है। मैं यह पता लगाने की कोशिश कर रहा हूं कि उबंटू पर कार्यक्षेत्र प्रति उपप्रकार कैसे फैलाना और मारना है। इस जवाब से मुझे मदद मिली। काश मैं इसे एक से अधिक बार उखाड़ सकता
सर्गियो कोलोडियाज़नी

2
अगर सेमी सेमी में प्रयोग नहीं किया जाता है तो यह काम नहीं करता है
gnr

@speedyrazor - विंडोज 10 पर काम नहीं करता है। मुझे लगता है कि ओएस विशिष्ट उत्तरों को स्पष्ट रूप से चिह्नित किया जाना चाहिए।
DarkLight

48

यदि आप psutil का उपयोग कर सकते हैं , तो यह पूरी तरह से काम करता है:

import subprocess

import psutil


def kill(proc_pid):
    process = psutil.Process(proc_pid)
    for proc in process.children(recursive=True):
        proc.kill()
    process.kill()


proc = subprocess.Popen(["infinite_app", "param"], shell=True)
try:
    proc.wait(timeout=3)
except subprocess.TimeoutExpired:
    kill(proc.pid)

3
AttributeError: 'Process' object has no attribute 'get_childrenके लिए pip install psutil
d33tah

3
मुझे लगता है कि get_children () बच्चे होने चाहिए ()। लेकिन यह विंडोज पर मेरे लिए काम नहीं करता था, प्रक्रिया अभी भी है।
गॉडस्मिथ

3
@Godsmith - psutil API बदल गया है और आप सही हैं: बच्चे () get_children () के रूप में एक ही काम करते हैं। यह विंडोज पर काम नहीं करता है, तो आप में एक बग टिकट बनाने के लिए चाहते हो सकता है GitHub
Jovik

24

मैं इसका उपयोग कर सकता है

from subprocess import Popen

process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))

इसने cmd.exeउस कार्यक्रम को मार दिया, जिसके लिए मैंने आज्ञा दी थी।

(विंडोज पर)


या प्रक्रिया नाम का उपयोग करें : Popen("TASKKILL /F /IM " + process_name)यदि आपके पास यह नहीं है, तो आप इसे commandपैरामीटर से प्राप्त कर सकते हैं ।
११:०४

12

जब shell=Trueशेल बाल प्रक्रिया है, और कमांड इसके बच्चे हैं। किसी भी तो SIGTERMया SIGKILLखोल मार डालेगा करती है लेकिन उसके बच्चे प्रक्रियाओं, और मैं एक अच्छा तरीका यह करने के लिए याद नहीं है। सबसे अच्छा तरीका मैं सोच सकता हूं कि इसका उपयोग करना है shell=False, अन्यथा जब आप मूल शेल प्रक्रिया को मारते हैं, तो यह एक दोषपूर्ण शेल प्रक्रिया को छोड़ देगा।


8

इस जवाब में से किसी ने मेरे लिए काम नहीं किया इसलिए इम ने उस कोड को छोड़ दिया जिसने काम किया। मेरे मामले में भी इस प्रक्रिया को मारने .kill()और .poll()रिटर्न कोड प्राप्त करने के बाद प्रक्रिया समाप्त नहीं हुई।

subprocess.Popen प्रलेखन के बाद :

"... ठीक से व्यवहार करने के लिए एक अच्छी तरह से व्यवहार किए गए एप्लिकेशन को बच्चे की प्रक्रिया को मारना चाहिए और संचार समाप्त करना चाहिए ..."

proc = subprocess.Popen(...)
try:
    outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
    proc.kill()
    outs, errs = proc.communicate()

मेरे मामले में मैं proc.communicate()फोन करने के बाद गायब था proc.kill()। यह प्रक्रिया स्टड, स्टडआउट को साफ करता है ... और प्रक्रिया को समाप्त करता है।


यह समाधान मेरे लिए Linux और python 2.7 में काम नहीं करता है
user9869932

@xyz इसने लिनक्स और अजगर 3.5 में मेरे लिए काम किया। अजगर 2.7 के लिए डॉक्स की जाँच करें
एपिनाल

@ उत्तर, धन्यवाद, हाँ। यह संभवतः एक लिनक्स मुद्दा है। यह रास्पबेरी 3 पर चल रहा है
उपयोगकर्ता 9869932

5

जैसा कि साई ने कहा, शेल बच्चा है, इसलिए संकेतों को इसके द्वारा इंटरसेप्ट किया जाता है - मैंने पाया सबसे अच्छा तरीका शेल = गलत का उपयोग करना और कमांड लाइन को विभाजित करने के लिए श्लेक्स का उपयोग करना है:

if isinstance(command, unicode):
    cmd = command.encode('utf8')
args = shlex.split(cmd)

p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

तब p.kill () और p.terminate () को वह कार्य करना चाहिए जो आप अपेक्षा करते हैं।


1
मेरे मामले में यह वास्तव में मदद नहीं करता है कि cmd "सीडी पथ और & zsync आदि" है। ताकि वास्तव में विफल करने के लिए आदेश बनाता है!
user175259

4
निर्देशिकाओं को बदलने के बजाय निरपेक्ष रास्तों का उपयोग करें ... वैकल्पिक रूप से os.chdir (...) उस निर्देशिका के लिए ...
Matt Billenstein

बच्चे की प्रक्रिया के लिए कामकाजी निर्देशिका को बदलने की क्षमता अंतर्निहित है। बस cwdतर्क को पास करो Popen
जोनाथन रेनहार्ट

मैंने श्लेक्स का इस्तेमाल किया, लेकिन फिर भी यह मुद्दा कायम है, मार बाल प्रक्रियाओं को नहीं मार रही है।
भूख लगी भूख

1

मुझे लगता है कि हम क्या उपयोग कर सकते हैं:

import os
import signal
import subprocess
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

os.killpg(os.getpgid(pro.pid), signal.SIGINT)

यह आपके सभी कार्य को नहीं बल्कि p.pid के साथ प्रक्रिया को मार देगा


0

मुझे पता है कि यह एक पुराना सवाल है लेकिन इससे किसी को अलग तरीके की तलाश करने में मदद मिल सकती है। यह वही है जो मैंने विंडोज़ पर उपयोग की जाने वाली प्रक्रियाओं को मारने के लिए उपयोग किया है।

si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.call(["taskkill", "/IM", "robocopy.exe", "/T", "/F"], startupinfo=si)

/ IM छवि का नाम है, आप चाहें तो PID भी कर सकते हैं। / टी प्रक्रिया को मारता है और साथ ही बच्चे को भी प्रक्रिया करता है। / एफ बल इसे समाप्त करता है। सी, जैसा कि मैंने इसे सेट किया है, सीएमडी विंडो दिखाए बिना आप यह कैसे करते हैं। इस कोड का उपयोग अजगर 3 में किया जाता है।


0

समूह में सभी प्रक्रियाओं के लिए संकेत भेजें

    self.proc = Popen(commands, 
            stdout=PIPE, 
            stderr=STDOUT, 
            universal_newlines=True, 
            preexec_fn=os.setsid)

    os.killpg(os.getpgid(self.proc.pid), signal.SIGHUP)
    os.killpg(os.getpgid(self.proc.pid), signal.SIGTERM)

0

मैंने इस उल्लेख को यहाँ नहीं देखा है, इसलिए मैं इसे वहाँ रख रहा हूँ जब किसी को इसकी आवश्यकता हो। यदि आप सभी को यह सुनिश्चित करना है कि आपका उपप्रकार सफलतापूर्वक समाप्त हो जाए, तो आप इसे एक संदर्भ प्रबंधक में रख सकते हैं। उदाहरण के लिए, मैं चाहता था कि मेरा मानक प्रिंटर एक छवि को प्रिंट करे और संदर्भ प्रबंधक का उपयोग करके सुनिश्चित करे कि उपप्रोसेस समाप्त हो गया।

import subprocess

with open(filename,'rb') as f:
    img=f.read()
with subprocess.Popen("/usr/bin/lpr", stdin=subprocess.PIPE) as lpr:
    lpr.stdin.write(img)
print('Printed image...')

मेरा मानना ​​है कि यह तरीका क्रॉस-प्लेटफॉर्म भी है।


मैं यह देखने में विफल हूं कि यहां कोड कैसे एक प्रक्रिया को समाप्त करता है। क्या आप स्पष्ट कर सकते हो?
DarkLight

मैंने स्पष्ट रूप से कहा है कि यदि आप सभी इसे करना चाहते हैं तो यह सुनिश्चित करता है कि आपके कोड की अगली पंक्ति में आगे बढ़ने से पहले आपकी प्रक्रिया समाप्त हो गई है, आप इस पद्धति का उपयोग कर सकते हैं। मैंने यह दावा नहीं किया कि यह प्रक्रिया को समाप्त करता है।
जयम शर्मा

संदर्भ प्रबंधक, जैसा कि आप स्पष्ट रूप से कहा है, "सुनिश्चित करें कि आपके प्रक्रिया समाप्त कर दिया है बनाता है" तो आप कर दावा है कि यह प्रक्रिया समाप्त हो जाता है। हालांकि यह करता है? यहां तक ​​कि जब shell=Trueप्रश्न के अनुसार प्रक्रिया शुरू की जाती है ? यह आपके कोड में नहीं है।
अपराह्न

anon, 'टर्मिनेटेड' शब्द के भ्रामक उपयोग को इंगित करने के लिए धन्यवाद। संदर्भ प्रबंधक अंतिम पंक्ति पर प्रिंट स्टेटमेंट पर जाने से पहले उपप्रकार के पूरा होने की प्रतीक्षा करता है। यह एक सिगटर की तरह कुछ का उपयोग करके प्रक्रिया को तुरंत समाप्त करने से अलग है। आप एक थ्रेड और कॉलिंग का उपयोग कर एक ही परिणाम हो सकता है thread.join()। आशा है कि यह इसे साफ करता है।
जयम शर्मा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.