শেল = ট্রু দিয়ে প্রবর্তিত পাইথন সাবপ্রসেসটি কীভাবে শেষ করা যায়


308

আমি নিম্নলিখিত কমান্ড সহ একটি সাব প্রসেস চালু করছি:

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

তবে, যখন আমি ব্যবহার করে হত্যা করার চেষ্টা করি:

p.terminate()

অথবা

p.kill()

কমান্ডটি পটভূমিতে চলতে থাকে, তাই আমি ভাবছিলাম যে আমি কীভাবে আসলে প্রক্রিয়াটি শেষ করতে পারি termin

মনে রাখবেন যে আমি যখন কমান্ডটি দিয়ে চালাব:

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
@ পাইওটারডব্রোগোস্ট: দুঃখের বিষয় না, কারণ os.setsidউইন্ডোজে পাওয়া যায় না ( ডকস.পাইথন.আর.লাইবারি /os.html#os.setsid ), আমি জানি না এটি সাহায্য করতে পারে কিনা তবে আপনি এখানে দেখতে পারেন ( বাগসপিপিথন.আরোগ / ইস্যু5115 ) এটি কীভাবে করবেন সে সম্পর্কে কিছু অন্তর্দৃষ্টির জন্য।
মওদ

6
এর সাথে কীভাবে subprocess.CREATE_NEW_PROCESS_GROUPসম্পর্কিত?
পাইটর ডব্রোগস্ট

11
আমাদের টেস্টিং সুগারসেটস যা সেটিড! = সেটপজিড এবং ওএস.পিজিকিলে কেবলমাত্র এমন উপ-প্রক্রিয়াগুলিকে হত্যা করে যা এখনও একই প্রক্রিয়া গ্রুপ আইডি রয়েছে। প্রক্রিয়া গোষ্ঠী পরিবর্তন করেছে এমন প্রক্রিয়া হত্যা করা হয় না, যদিও তাদের এখনও একই সেশন আইডি থাকতে পারে ...
এইচডাব্লু


4
আমি os.setsid () করার সুপারিশ করব না, কারণ এটির অন্যান্য প্রভাবও রয়েছে। অন্যদের মধ্যে এটি নিয়ন্ত্রণকারী টিটিওয়াই সংযোগ বিচ্ছিন্ন করে এবং নতুন প্রক্রিয়াটিকে একটি প্রক্রিয়া গ্রুপের নেতা করে তোলে। দেখুন win.tue.nl/~aeb/linux/lk/lk-10.html
parasietje

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)

এটি শেল প্রক্রিয়াটি শেল প্রসেসের পরিবর্তে শেল প্রক্রিয়াটি উত্তরাধিকার সূত্রে পরিণত করবে, যা মারা না যায়। p.pidতখন আপনার সিএমডি প্রক্রিয়াটির আইডি হবে।

p.kill() কাজ করা উচিত.

যদিও আপনার পাইপে এটির কী প্রভাব ফেলবে আমি জানি না।


1
* নিক্সের জন্য দুর্দান্ত এবং হালকা সমাধান, ধন্যবাদ! লিনাক্সে কাজ করে, ম্যাকের জন্যও কাজ করা উচিত।
মারসফট

খুব সুন্দর সমাধান। যদি আপনার সেন্টিমিডিটি অন্য কোনও কিছুর জন্য শেল স্ক্রিপ্টের মোড়ক হিসাবে ঘটে থাকে তবে কেবলমাত্র একটি সাবপ্রসেসের জন্য এক্সিকিউট সহ চূড়ান্ত বাইনারিটি কল করুন।
নিকোলিনাক্স

1
এটা সুন্দর. আমি কীভাবে উবুন্টুতে ওয়ার্কস্পেসে সাব-প্রসেসকে স্পোন করে মেরে ফেলতে পারি তা জানার চেষ্টা করছি। এই উত্তরটি আমাকে সাহায্য করেছিল। আশা করি আমি এটি একাধিকবার উপার্জন করতে পারতাম
সের্গেই কলডিয়াজনি


@ স্পিডায়রাজার - উইন্ডোজ 10 এ কাজ করে না। আমি মনে করি ওএস নির্দিষ্ট উত্তরগুলি পরিষ্কারভাবে চিহ্নিত করা উচিত।
ডার্কলাইট

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
@ গুডস্মিথ - psutil এপিআই পরিবর্তন হয়েছে এবং আপনি ঠিক বলেছেন: বাচ্চারা () get_children () এর মতো একই কাজ করে। যদি এটি উইন্ডোজটিতে কাজ না করে, তবে আপনি গিটহাব
জোভিক

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প্যারামিটার থেকে পেতে পারেন ।
zvi

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()। এটি প্রক্রিয়াটি স্টিন, স্টডআউট ... পরিষ্কার করে এবং প্রক্রিয়াটি সমাপ্ত করে।


এই সমাধানটি আমার জন্য লিনাক্স এবং পাইথন ২.7
user9869932

@xyz এটি আমার জন্য লিনাক্স এবং অজগর 3.5 তে কাজ করেছিল। অজগর ২.7 এর জন্য
ডকগুলি

@ স্পিনাল, ধন্যবাদ, হ্যাঁ এটি সম্ভবত একটি লিনাক্স সমস্যা। এটি
রাস্পবিয়ান লিনাক্সটি

5

সাঁই যেমন বলেছেন, শেলটি শিশু, তাই এটির দ্বারা সংকেতগুলি বাধা দেওয়া হয় - আমি খুঁজে পেয়েছি সেরা উপায় শেল = মিথ্যা এবং কমান্ড লাইনের বিভাজনে শ্লেক্স ব্যবহার করা:

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

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

তারপরে পি.কিল () এবং পি.টার্মিনেট () আপনার প্রত্যাশা মতো কাজ করবে।


1
আমার ক্ষেত্রে এটি সত্যিকার অর্থে সহায়তা করে না যে সেন্টিমিডিটি "সিডি পাথ এবং & zsync ইত্যাদি"। যাতে আসলে কমান্ডটি ব্যর্থ হয়!
user175259

4
ডিরেক্টরি পরিবর্তন করার পরিবর্তে নিখুঁত পাথ ব্যবহার করুন ... thatচ্ছিকভাবে সেই ডিরেক্টরিতে os.chdir (...) ...
ম্যাট বিলেনস্টেইন

শিশু প্রক্রিয়াটির জন্য ওয়ার্কিং ডিরেক্টরি পরিবর্তন করার ক্ষমতা অন্তর্নির্মিত। শুধু cwdযুক্তি পাস Popen
জোনাথন রেইনার্ট

আমি নমনীয় ব্যবহার করেছি, তবে এখনও সমস্যাটি অব্যাহত রয়েছে, হত্যা শিশু প্রক্রিয়াগুলিকে হত্যা করে না।
ক্ষুধার্ত ওল্ফ 25'17

1

আমরা যেমনটি ব্যবহার করতে পারি তেমন আমার মনে হয়:

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

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

এটি আপনার সমস্ত টাস্ককে হত্যা করবে না তবে পিপিড দিয়ে প্রক্রিয়া করবে


0

আমি জানি এটি একটি পুরানো প্রশ্ন তবে এটি কোনও আলাদা পদ্ধতি অনুসন্ধানে কাউকে সহায়তা করতে পারে। আমি কল করেছি এমন প্রক্রিয়াগুলি হ্রাস করতে আমি উইন্ডোতে এটি ব্যবহার করি।

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

/ আইএম চিত্রটির নাম, আপনি চাইলে / পিআইডিও করতে পারেন। / টি প্রক্রিয়াটি পাশাপাশি শিশু প্রক্রিয়াগুলিকে মেরে ফেলে। / এফ ফোর্স এটি শেষ করে। তবে, আমার যেমন এটি সেট আছে ঠিক তেমনই কোনও সিএমডি উইন্ডো না দেখিয়ে আপনি কীভাবে তা করেন। অজগর 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...')

আমি বিশ্বাস করি যে এই পদ্ধতিটি ক্রস প্ল্যাটফর্মও।


আমি এখানে কোড কীভাবে একটি প্রক্রিয়া শেষ করে তা দেখতে ব্যর্থ হয়েছি। আপনি কি স্পষ্ট করতে পারেন?
ডার্কলাইট

আমি স্পষ্টভাবে বলেছি যে আপনি যদি এটি করতে চান তবে আপনার কোডের পরবর্তী লাইনে যাওয়ার আগে আপনার প্রক্রিয়াটি বন্ধ হয়ে গেছে কিনা তা নিশ্চিত করে নিন, আপনি এই পদ্ধতিটি ব্যবহার করতে পারেন। আমি দাবি করি নি যে এটি প্রক্রিয়াটি শেষ করে।
জয়য়াম শর্মা

প্রসঙ্গ ম্যানেজার হিসাবে আপনি পরিষ্কারভাবে বলেছেন, "নিশ্চিত করুন যে আপনার প্রক্রিয়া সমাপ্ত হয়েছে তোলে" তাহলে কি বলে যে দাবি করা এটি প্রক্রিয়া বন্ধ। এটা যদিও না? এমনকি প্রক্রিয়াটি চালু করা shell=Trueহলেও, প্রশ্ন অনুযায়ী? যার ফলে এটি নয় আপনার কোডে।
আনোন

আনন, 'টার্মিনেটেড' শব্দের বিভ্রান্তিকর ব্যবহারটি নির্দেশ করার জন্য আপনাকে ধন্যবাদ। প্রসঙ্গ পরিচালকটি শেষ লাইনে মুদ্রণ বিবৃতিতে যাওয়ার আগে সাবপ্রসেসটি সম্পন্ন হওয়ার জন্য অপেক্ষা করে। এটি একটি সিগটারমের মতো কিছু ব্যবহার করে তাত্ক্ষণিকভাবে প্রক্রিয়াটি সমাপ্ত করা থেকে পৃথক। থ্রেড এবং কলিং ব্যবহার করে আপনার একই ফলাফল হতে পারে thread.join()। আশা করি এটি পরিষ্কার হয়ে যাবে।
জয়য়াম শর্মা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.