পাইথন থেকে আমি কীভাবে একটি বহিরাগত কমান্ড অবিচ্ছিন্নভাবে চালাতে পারি?


120

পাইথনের স্ক্রিপ্ট থেকে আমার শিন কমান্ড অ্যাসিঙ্ক্রোনসিভভাবে চালানো দরকার। এর মাধ্যমে আমি বোঝাতে চাইছি যে আমি বাহ্যিক কমান্ডটি বন্ধ হয়ে যাওয়ার পরে আমার পাইথন স্ক্রিপ্টটি চালিয়ে যেতে চাই এবং যা যা করা দরকার তা করে।

আমি এই পোস্টটি পড়েছি:

পাইথনে একটি বাহ্যিক কমান্ড কল করা

আমি তখন গিয়েছিলাম এবং কিছু পরীক্ষা করেছি এবং দেখে মনে হচ্ছে os.system()যে &কমান্ডের শেষে আমি যে কাজটি ব্যবহার করি তা করব যাতে করে এটি ফিরে আসার অপেক্ষা রাখে না। আমি যা ভাবছি তা হ'ল যদি এই জাতীয় জিনিসটি সম্পাদন করার উপযুক্ত উপায় হয়? আমি চেষ্টা করেছিলাম commands.call()কিন্তু এটি আমার পক্ষে কার্যকর হবে না কারণ এটি বাহ্যিক কমান্ডে অবরুদ্ধ।

os.system()এটির জন্য ব্যবহার করার পরামর্শ দেওয়া হয় বা অন্য কোনও রুট চেষ্টা করা উচিত কিনা দয়া করে আমাকে জানান ।

উত্তর:


135

সাবপ্রসেস.পোপেন আপনি যা চান ঠিক তেমন করে।

from subprocess import Popen
p = Popen(['watch', 'ls']) # something long running
# ... do other stuff while subprocess is running
p.terminate()

(মন্তব্যগুলি থেকে উত্তর সম্পূর্ণ করতে সম্পাদনা করুন)

পোপেন উদাহরণটি অন্যান্য বিভিন্ন কাজ করতে পারে যেমন আপনি poll()এটি এখনও চলছে কিনা তা দেখতে আপনি এটি করতে পারেন এবং স্টিডিনে communicate()এটি ডেটা প্রেরণ করার জন্য আপনি এটি দিয়ে করতে পারেন এবং এটি শেষ হওয়ার জন্য অপেক্ষা করুন।


4
সন্তানের প্রক্রিয়াটি বন্ধ হয়ে গেছে কিনা তা পরীক্ষা করতে আপনিও জরিপ () ব্যবহার করতে পারেন, বা এটি বন্ধ হওয়ার জন্য অপেক্ষা করতে অপেক্ষা () ব্যবহার করতে পারেন।
অ্যাডাম রোজেনফিল্ড

অ্যাডাম, খুব সত্য, যদিও যোগাযোগ () অপেক্ষা করার জন্য এটি আরও ভাল হতে পারে কারণ এর মধ্যে / আউট বাফারগুলিতে ভাল পরিচালনা করা এবং এমন পরিস্থিতি রয়েছে যেখানে এগুলি বন্যার ফলে ব্লক হতে পারে।
আলী আফশার

আদম: ডক্স "সতর্কবাণী যদি সন্তান প্রক্রিয়া একটি stdout- এ বা দ্বারা stderr নল যথেষ্ট আউটপুট যেমন যে এটা OS নল জন্য অপেক্ষা ব্লক আরো ডেটা গ্রহণ করতে বাফার তৈরি করে এই অচলাবস্থা হবে ব্যবহারের যোগাযোগ () যে এড়ানো।।" বলুন
আলী Afshar

14
যোগাযোগ করুন () এবং অপেক্ষা () অপারেশনটিকে অবরুদ্ধ করছে, যদিও। আপনি ওপেনগুলি ব্যবহার করেন কিনা এমন জিজ্ঞাসা করার মতো আপনি সমান্তরাল কমান্ডগুলি হবেন না।
সিডলারি

1
সিডলারি একেবারে সঠিক, এটি উল্লেখ করা উচিত যে যোগাযোগ এবং অপেক্ষা কর ডু ব্লক, সুতরাং যখন আপনি জিনিসগুলি বন্ধ করার জন্য অপেক্ষা করছেন তখনই এটি করুন। (যা আপনার সত্যিকারের আচরণের জন্য সত্যই করা উচিত)
আলী আফশার

48

আপনি যদি সমান্তরালভাবে অনেকগুলি প্রক্রিয়া চালাতে চান এবং তারপরে ফলাফল আসে তখন সেগুলি পরিচালনা করেন, আপনি নীচের মত পোলিং ব্যবহার করতে পারেন:

from subprocess import Popen, PIPE
import time

running_procs = [
    Popen(['/usr/bin/my_cmd', '-i %s' % path], stdout=PIPE, stderr=PIPE)
    for path in '/tmp/file0 /tmp/file1 /tmp/file2'.split()]

while running_procs:
    for proc in running_procs:
        retcode = proc.poll()
        if retcode is not None: # Process finished.
            running_procs.remove(proc)
            break
        else: # No process is done, wait a bit and check again.
            time.sleep(.1)
            continue

    # Here, `proc` has finished with return code `retcode`
    if retcode != 0:
        """Error handling."""
    handle_results(proc.stdout)

সেখানকার নিয়ন্ত্রণ প্রবাহটি কিছুটা বিশৃঙ্খলাযুক্ত কারণ আমি এটিকে ছোট করার চেষ্টা করছি - আপনি আপনার স্বাদটি রিফেক্টর করতে পারেন। :-)

প্রথমে প্রথম দিকে শেষ করার অনুরোধগুলি পরিবেশন করার সুবিধা রয়েছে। আপনি যদি communicateপ্রথম চলমান প্রক্রিয়াটি কল করেন এবং এটি সবচেয়ে দীর্ঘস্থায়ীভাবে পরিচালিত হয়, আপনি যখন ফলাফলগুলি পরিচালনা করতে পারতেন তখন অন্যান্য চলমান প্রক্রিয়াগুলি অলস হয়ে বসে থাকবে।


3
@ টিনো এটি কীভাবে আপনি ব্যস্ত-অপেক্ষাকে সংজ্ঞায়িত করেন তার উপর নির্ভর করে। ব্যস্ততা এবং ভোটগ্রহণের মধ্যে পার্থক্য কী
পাইওটার ডব্রোগস্ট

1
একমাত্র প্রক্রিয়াগুলির সেটগুলিকে পোল করার কোনও উপায় আছে কি?
পাইওটার ডব্রোগোস্ট

1
দ্রষ্টব্য: কোনও প্রক্রিয়া পর্যাপ্ত আউটপুট উৎপন্ন করলে এটি স্তব্ধ হয়ে যেতে পারে। আপনি পাইপই ব্যবহার করেন (একই সাথে সাবপ্রসেসের ডক্সে সতর্কতা রয়েছে)
jfs

@ পাইওটারডব্রোগোস্ট: আপনি os.waitpidসরাসরি ব্যবহার করতে পারেন যা কোনও শিশু প্রক্রিয়া তার অবস্থার পরিবর্তন করেছে কিনা তা খতিয়ে দেখার অনুমতি দেয় ।
jfs

5
ব্যবহার ['/usr/bin/my_cmd', '-i', path]পরিবর্তে['/usr/bin/my_cmd', '-i %s' % path]
JFS

11

আমি যা ভাবছি তা হ'ল যদি এই [ওএস.সিস্টেম ()] এই জাতীয় কাজটি সম্পাদন করার উপযুক্ত উপায়?

নং os.system()সঠিক পথ নয়। এজন্য প্রত্যেকে ব্যবহার করতে বলে subprocess

আরও তথ্যের জন্য, http://docs.python.org/library/os.html#os.system পড়ুন

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


8

অ্যাসিঙ্কপ্রোক মডিউলটির সাথে আমার ভাল সাফল্য আছে , যা প্রক্রিয়াগুলি থেকে আউটপুট নিয়ে দুর্দান্তভাবে কাজ করে। উদাহরণ স্বরূপ:

import os
from asynproc import Process
myProc = Process("myprogram.app")

while True:
    # check to see if process has ended
    poll = myProc.wait(os.WNOHANG)
    if poll is not None:
        break
    # print any new output
    out = myProc.read()
    if out != "":
        print out

এটা কি গিথুবের কোথাও?
নিক

এটি জিপিএল লাইসেন্স, তাই আমি নিশ্চিত যে এটি সেখানে অনেকবার রয়েছে। এখানে একটি: github.com/albertz/helpers/blob/master/asyncproc.py
নোহ

পাইথন 3 দিয়ে কাজ করার জন্য আমি কিছু সংশোধন সহ একটি টুকরো যোগ করেছি। (বেশিরভাগ ক্ষেত্রে বাইট দিয়ে স্ট্রিং প্রতিস্থাপন)) দেখুন gist.github.com/grandemk/cbc528719e46b5a0ffbd07e3054aab83
শিরাসমূহের

1
এছাড়াও, লুপের বাইরে যাওয়ার পরে আপনাকে আরও একবার আউটপুট পড়তে হবে বা আপনি কিছু আউটপুট হারাবেন।
টিকিট

7

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


4

"এটি ফিরে আসার জন্য আমাকে অপেক্ষা করতে হবে না" বিবেচনা করে, অন্যতম সহজ সমাধান হ'ল:

subprocess.Popen( \
    [path_to_executable, arg1, arg2, ... argN],
    creationflags = subprocess.CREATE_NEW_CONSOLE,
).pid

তবে ... আমি যা পড়েছি তা থেকে subprocess.CREATE_NEW_CONSOLEপতাকা দ্বারা তৈরি সুরক্ষা ঝুঁকির কারণে "এই জাতীয় কাজটি করার সঠিক উপায়" নয় ।

এখানে ঘটে যাওয়া মূল বিষয়গুলি হ'ল subprocess.CREATE_NEW_CONSOLEনতুন কনসোল তৈরি করতে ব্যবহার করা এবং .pid(প্রক্রিয়া আইডি রিটার্ন যাতে আপনি চাইলে পরে প্রোগ্রাম পরীক্ষা করতে পারেন) যাতে প্রোগ্রামটির কাজ শেষ হওয়ার জন্য অপেক্ষা না করা।


3

পাইথনের এস 3270 স্ক্রিপ্টিং সফ্টওয়্যারটি ব্যবহার করে 3270 টার্মিনালের সাথে সংযোগ স্থাপনের চেষ্টা করতে আমার একই সমস্যা রয়েছে। এখন আমি এখানে প্রক্রিয়াটির একটি সাবক্লাস দিয়ে সমস্যার সমাধান করছি:

http://code.activestate.com/recipes/440554/

এবং ফাইল থেকে নেওয়া নমুনা এখানে:

def recv_some(p, t=.1, e=1, tr=5, stderr=0):
    if tr < 1:
        tr = 1
    x = time.time()+t
    y = []
    r = ''
    pr = p.recv
    if stderr:
        pr = p.recv_err
    while time.time() < x or r:
        r = pr()
        if r is None:
            if e:
                raise Exception(message)
            else:
                break
        elif r:
            y.append(r)
        else:
            time.sleep(max((x-time.time())/tr, 0))
    return ''.join(y)

def send_all(p, data):
    while len(data):
        sent = p.send(data)
        if sent is None:
            raise Exception(message)
        data = buffer(data, sent)

if __name__ == '__main__':
    if sys.platform == 'win32':
        shell, commands, tail = ('cmd', ('dir /w', 'echo HELLO WORLD'), '\r\n')
    else:
        shell, commands, tail = ('sh', ('ls', 'echo HELLO WORLD'), '\n')

    a = Popen(shell, stdin=PIPE, stdout=PIPE)
    print recv_some(a),
    for cmd in commands:
        send_all(a, cmd + tail)
        print recv_some(a),
    send_all(a, 'exit' + tail)
    print recv_some(a, e=0)
    a.wait()

3

গৃহীত উত্তরটি খুব পুরানো।

আমি এখানে একটি আরও আধুনিক উত্তর খুঁজে পেয়েছি:

https://kevinmccarthy.org/2016/07/25/streaming-subprocess-stdin-and-stdout-with-asyncio-in-python/

এবং কিছু পরিবর্তন করেছেন:

  1. এটি উইন্ডোতে কাজ করা
  2. এটি একাধিক কমান্ড দিয়ে কাজ করা
import sys
import asyncio

if sys.platform == "win32":
    asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())


async def _read_stream(stream, cb):
    while True:
        line = await stream.readline()
        if line:
            cb(line)
        else:
            break


async def _stream_subprocess(cmd, stdout_cb, stderr_cb):
    try:
        process = await asyncio.create_subprocess_exec(
            *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
        )

        await asyncio.wait(
            [
                _read_stream(process.stdout, stdout_cb),
                _read_stream(process.stderr, stderr_cb),
            ]
        )
        rc = await process.wait()
        return process.pid, rc
    except OSError as e:
        # the program will hang if we let any exception propagate
        return e


def execute(*aws):
    """ run the given coroutines in an asyncio loop
    returns a list containing the values returned from each coroutine.
    """
    loop = asyncio.get_event_loop()
    rc = loop.run_until_complete(asyncio.gather(*aws))
    loop.close()
    return rc


def printer(label):
    def pr(*args, **kw):
        print(label, *args, **kw)

    return pr


def name_it(start=0, template="s{}"):
    """a simple generator for task names
    """
    while True:
        yield template.format(start)
        start += 1


def runners(cmds):
    """
    cmds is a list of commands to excecute as subprocesses
    each item is a list appropriate for use by subprocess.call
    """
    next_name = name_it().__next__
    for cmd in cmds:
        name = next_name()
        out = printer(f"{name}.stdout")
        err = printer(f"{name}.stderr")
        yield _stream_subprocess(cmd, out, err)


if __name__ == "__main__":
    cmds = (
        [
            "sh",
            "-c",
            """echo "$SHELL"-stdout && sleep 1 && echo stderr 1>&2 && sleep 1 && echo done""",
        ],
        [
            "bash",
            "-c",
            "echo 'hello, Dave.' && sleep 1 && echo dave_err 1>&2 && sleep 1 && echo done",
        ],
        [sys.executable, "-c", 'print("hello from python");import sys;sys.exit(2)'],
    )

    print(execute(*runners(cmds)))

উদাহরণস্বরূপ কমান্ডগুলি আপনার সিস্টেমে নিখুঁতভাবে কাজ করবে এটি অসম্ভব এবং এটি অদ্ভুত ত্রুটিগুলি পরিচালনা করে না, তবে এই কোডটি অ্যাসিনসিও ব্যবহার করে একাধিক সাবপ্রসেসি চালানোর এবং আউটপুট প্রবাহিত করার এক উপায় প্রদর্শন করে।


আমি এটি উইন্ডোতে চালিত সিপাইথন ৩.7.৪ এবং সিপাইথন ৩.7.৩ এ উবুন্টু ডাব্লুএসএল এবং নেটিভ আলপাইন লিনাক্সে চলতে দেখেছি
টেরেল শামওয়ে


1

এখানে বেশ কয়েকটি উত্তর রয়েছে তবে এর মধ্যে কেউই আমার নীচের প্রয়োজনীয়তাগুলি পূরণ করে নি:

  1. সাব-প্রসেস আউটপুটগুলি দিয়ে আমার টার্মিনালটি সমাপ্ত বা দূষিত করার জন্য আমি কমান্ডের অপেক্ষা করতে চাই না।

  2. আমি পুনর্নির্দেশগুলি সহ বাশ স্ক্রিপ্টটি চালাতে চাই।

  3. আমি আমার বাশ স্ক্রিপ্টের মধ্যে পাইপিং সমর্থন করতে চাই (উদাহরণস্বরূপ find ... | tar ...)।

প্রয়োজনীয়তাগুলির উপরে combinationক্যবদ্ধ একমাত্র সংমিশ্রণটি হ'ল:

subprocess.Popen(['./my_script.sh "arg1" > "redirect/path/to"'],
                 stdout=subprocess.PIPE, 
                 stderr=subprocess.PIPE,
                 shell=True)

0

এটি পাইপথন 3 সাবপ্রসেসি উদাহরণগুলি " সংশ্লেষকভাবে সমাপ্ত করার জন্য কমান্ডের জন্য অপেক্ষা করুন" এর অধীনে আচ্ছাদিত :

import asyncio

proc = await asyncio.create_subprocess_exec(
    'ls','-lha',
    stdout=asyncio.subprocess.PIPE,
    stderr=asyncio.subprocess.PIPE)

# do something else while ls is working

# if proc takes very long to complete, the CPUs are free to use cycles for 
# other processes
stdout, stderr = await proc.communicate()

প্রক্রিয়াটি শেষ হওয়ার সাথে সাথে চলতে শুরু করবে await asyncio.create_subprocess_exec(...)। আপনি কল করার সময় যদি এটি শেষ না হয় তবে await proc.communicate()আপনাকে আপনার আউটপুট স্থিতি দেওয়ার জন্য এটি সেখানে অপেক্ষা করবে। এটি শেষ হলে,proc.communicate() অবিলম্বে ফিরে আসবে।

এখানে সংক্ষিপ্তসার টেরেল উত্তর অনুরূপ তবে আমি মনে করি টেরেলস উত্তরটি জটিল জিনিসগুলিকে দেখে মনে হচ্ছে।

দেখুন asyncio.create_subprocess_execআরও তথ্যের জন্য।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.