শেল কমান্ড চলছে এবং আউটপুট ক্যাপচার করছে


905

আমি এমন একটি ফাংশন লিখতে চাই যা শেল কমান্ড কার্যকর করবে এবং তার আউটপুটটিকে স্ট্রিং হিসাবে ফিরিয়ে দেবে , এটি কোনও ত্রুটি বা সাফল্যের বার্তা matter আমি কেবল একই ফলটি পেতে চাই যা আমি কমান্ড লাইনের সাথে পেয়েছি।

এমন একটি কোড উদাহরণস্বরূপ কী হবে?

উদাহরণ স্বরূপ:

def run_command(cmd):
    # ??????

print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'

2
সম্পর্কিত: stackoverflow.com/questions/2924310/...
JFS

উত্তর:


1137

এই প্রশ্নের উত্তরটি আপনি ব্যবহার করছেন পাইথনের সংস্করণে on সবচেয়ে সহজ পদ্ধতির হ'ল subprocess.check_outputফাংশনটি ব্যবহার করা :

>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

check_outputএকটি একক প্রোগ্রাম চালায় যা ইনপুট হিসাবে কেবল আর্গুমেন্ট নেয়। 1 এটি মুদ্রিত হিসাবে ফলাফল ঠিক ফেরত দেয় stdout। আপনার যদি ইনপুট লেখার দরকার পড়ে stdinতবে বিভাগ runবা Popenবিভাগগুলিতে যান। আপনি যদি জটিল শেল কমান্ডগুলি কার্যকর করতে চান shell=Trueতবে এই উত্তরটির শেষে নোটটি দেখুন ।

check_outputফাংশন এখনও ব্যাপক ব্যবহার (2.7+) এ Python- র প্রায় সব সংস্করণের উপর কাজ করে। 2 তবে সাম্প্রতিক সংস্করণগুলির জন্য এটি আর প্রস্তাবিত পদ্ধতির নয় is

পাইথনের আধুনিক সংস্করণ (3.5 বা তার বেশি): run

আপনি যদি পাইথন 3.5 বা তার বেশি ব্যবহার করেন এবং পিছনের দিকে সামঞ্জস্যের প্রয়োজন না হয় তবে নতুন runফাংশনটি প্রস্তাবিত। এটি subprocessমডিউলটির জন্য একটি খুব সাধারণ, উচ্চ-স্তরের এপিআই সরবরাহ করে । কোনও প্রোগ্রামের আউটপুট ক্যাপচার subprocess.PIPEকরতে, stdoutকীওয়ার্ড আর্গুমেন্টে পতাকাটি পাস করুন । তারপরে stdoutপ্রত্যাবর্তিত CompletedProcessঅবজেক্টের বৈশিষ্ট্যটি অ্যাক্সেস করুন :

>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

রিটার্ন মান হ'ল একটি bytesঅবজেক্ট, সুতরাং আপনি যদি একটি সঠিক স্ট্রিং চান, আপনার decodeএটি দরকার । কল করা প্রক্রিয়াটি ধরে নেওয়া একটি ইউটিএফ-8-এনকোডযুক্ত স্ট্রিং প্রদান করে:

>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

এটি সমস্তই ওয়ান-লাইনারে সংকুচিত হতে পারে:

>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

আপনি যদি প্রক্রিয়াটির ইনপুটটি পাস করতে চান তবে কী- ওয়ার্ড আর্গুমেন্টে stdinকোনও bytesবস্তুটি পাস করুন input:

>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'

আপনি পাস করার মাধ্যমে ত্রুটি ক্যাপচার করতে পারেন stderr=subprocess.PIPE(ক্যাপচারে result.stderr) বা stderr=subprocess.STDOUT( result.stdoutনিয়মিত আউটপুট সহ ক্যাপচার )। যখন সুরক্ষা কোনও উদ্বেগের বিষয় নয়, আপনি shell=Trueনীচের নোটগুলিতে বর্ণিত হিসাবে পাস করে আরও জটিল শেল কমান্ড পরিচালনা করতে পারেন ।

জিনিসগুলি করার পুরানো পদ্ধতির তুলনায় এটি কিছুটা জটিলতা যুক্ত করে। তবে আমি মনে করি এটি পরিশোধের পক্ষে মূল্যবান: এখন আপনি runকেবলমাত্র ফাংশনটি নিয়ে যা করতে হবে তা করতে পারেন ।

পাইথনের পুরানো সংস্করণ (২.7-৩.৪): check_output

আপনি যদি পাইথনের একটি পুরানো সংস্করণ ব্যবহার করছেন, বা সামান্য পিছনে সামঞ্জস্যের প্রয়োজন হয়, আপনি সম্ভবত check_outputউপরে সংক্ষেপে বর্ণিত হিসাবে ফাংশনটি ব্যবহার করতে পারেন । পাইথন ২. 2. থেকে এটি উপলব্ধ।

subprocess.check_output(*popenargs, **kwargs)  

এটি Popen(নীচে দেখুন) হিসাবে একই আর্গুমেন্ট নেয় এবং প্রোগ্রামটির আউটপুট সমেত একটি স্ট্রিং দেয়। এই উত্তরের শুরুতে আরও বিশদ ব্যবহারের উদাহরণ রয়েছে। পাইথন ৩.৫ এবং তার চেয়েও বড় ক্ষেত্রে check_outputএটি কার্যকর runকরা check=Trueএবং stdout=PIPEঠিক stdoutঅ্যাট্রিবিউট ফিরিয়ে দেওয়ার সমতুল্য ।

stderr=subprocess.STDOUTফিরে আসা আউটপুটটিতে ত্রুটি বার্তাগুলি অন্তর্ভুক্ত রয়েছে তা নিশ্চিত করতে আপনি পাস করতে পারেন - তবে পাইথনের কয়েকটি সংস্করণে পাস stderr=subprocess.PIPEকরার check_outputফলে ডেডলক হতে পারে । যখন সুরক্ষা কোনও উদ্বেগের বিষয় নয়, আপনি shell=Trueনীচের নোটগুলিতে বর্ণিত হিসাবে পাস করে আরও জটিল শেল কমান্ড পরিচালনা করতে পারেন ।

আপনি যদি stderrপ্রক্রিয়াটি থেকে পাইপ বা ইনপুট পাস করার প্রয়োজন check_outputহয় তবে কাজটি শেষ হবে না। এক্ষেত্রে Popenনীচের উদাহরণগুলি দেখুন ।

জটিল অ্যাপ্লিকেশন এবং পাইথনের উত্তরাধিকার সংস্করণ (২.6 এবং নীচে): Popen

আপনার যদি গভীর পিছনের সামঞ্জস্যতা প্রয়োজন হয়, বা যদি সরবরাহের তুলনায় আপনার আরও পরিশীলিত কার্যকারিতা প্রয়োজন হয় তবে আপনাকে অবজেক্টগুলির check_outputসাথে সরাসরি কাজ করতে হবে Popen, যা উপ-প্রক্রিয়াগুলির জন্য নিম্ন-স্তরের এপিআইকে আবদ্ধ করে।

Popenকন্সট্রাকটর পারেন গ্রহণ একটি কমান্ডের আর্গুমেন্ট ছাড়া, অথবা একটি তালিকা তার প্রথম আইটেম হিসাবে কমান্ড যুক্তি যে কোন সংখ্যার তালিকা একটি পৃথক আইটেম হিসাবে প্রতিটি দ্বারা অনুসরণ রয়েছে। shlex.splitস্ট্রিংগুলি যথাযথভাবে ফর্ম্যাট করা তালিকায় পার্স করতে সহায়তা করতে পারে। প্রক্রিয়া আইও পরিচালনা এবং নিম্ন-স্তরের কনফিগারেশনের জন্য Popenঅবজেক্টগুলি বিভিন্ন আর্গুমেন্টও গ্রহণ করে ।

ইনপুট এবং ক্যাপচার আউটপুট প্রেরণ, communicateপ্রায় সবসময় পছন্দসই পদ্ধতি। যেমন:

output = subprocess.Popen(["mycmd", "myarg"], 
                          stdout=subprocess.PIPE).communicate()[0]

অথবা

>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, 
...                                    stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo

আপনি সেট করেন তাহলে stdin=PIPE, communicateএছাড়াও আপনি মাধ্যমে প্রক্রিয়া তথ্য প্রেরণ করতে পারবেন stdin:

>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
...                           stderr=subprocess.PIPE,
...                           stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo

নোট হারুন হলের উত্তর , যা নির্দেশ করে কিছু সিস্টেমে, আপনি সেট করার প্রয়োজন হতে পারে stdout, stderrএবং stdinসব থেকে PIPE(অথবা DEVNULL) পেতে communicateকাজ সব সময়ে।

কিছু বিরল ক্ষেত্রে আপনার জটিল, রিয়েল-টাইম আউটপুট ক্যাপচারের প্রয়োজন হতে পারে। ভার্টেকের উত্তরটি সামনের দিকে এগিয়ে যাওয়ার উপায় নির্দেশ করে, তবে communicateসাবধানতার সাথে ব্যবহার না করা হলে অন্যান্য পদ্ধতিগুলি অচলাবস্থার ঝুঁকির মধ্যে রয়েছে।

উপরের সমস্ত ফাংশনগুলির মতো, যখন সুরক্ষা কোনও উদ্বেগের বিষয় নয়, আপনি পাশ দিয়ে আরও জটিল শেল কমান্ড চালাতে পারেন shell=True

মন্তব্য

1. চালানো শেল কমান্ড: shell=Trueযুক্তি

সাধারণত, এর প্রতিটি কলের run, check_outputঅথবা Popenকন্সট্রাকটর একটি executes একক কর্মসূচি । এর অর্থ কোনও অভিনব বাশ-স্টাইলের পাইপ নেই। আপনি যদি জটিল শেল কমান্ডগুলি চালাতে চান তবে আপনি পাস করতে পারেন shell=True, যা তিনটি ফাংশনই সমর্থন করে।

তবে, এটি করা সুরক্ষা উদ্বেগ উত্থাপন করে । আপনি যদি হালকা স্ক্রিপ্টিংয়ের চেয়ে আরও কিছু করে থাকেন তবে আপনি প্রতিটি প্রক্রিয়া আলাদাভাবে কল করা এবং প্রতিটি থেকে আউটপুটটিকে পরবর্তী ইনপুট হিসাবে পাস করার মাধ্যমে ভাল করতে পারেন via

run(cmd, [stdout=etc...], input=other_output)

অথবা

Popen(cmd, [stdout=etc...]).communicate(other_output)

পাইপগুলিকে সরাসরি সংযুক্ত করার লোভ প্রবল; এটি প্রতিহত করুন। অন্যথায়, আপনি সম্ভবত ডেডলকগুলি দেখতে পাবেন বা এই জাতীয় কিছু করতে হবে ।

2. ইউনিকোড বিবেচনা

check_outputপাইথন 2 এ স্ট্রিং দেয়, কিন্তু পাইথন 3-এ একটি bytesঅবজেক্ট un আপনি যদি ইতিমধ্যে না থাকেন তবে ইউনিকোড সম্পর্কে জানতে কিছুটা সময় নেওয়া উচিত


5
প্রক্রিয়াটি শেষ না হওয়া পর্যন্ত check_output()এবং উভয়ই communicate()আপনাকে অপেক্ষা করতে হবে, poll()আপনি যেমন আউটপুট আসছেন ততক্ষণে। আপনার যা প্রয়োজন তা নির্ভর করে।
9

2
এটি কেবল পাইথনের পরবর্তী সংস্করণগুলিতে প্রযোজ্য কিনা তা নিশ্চিত নয়, তবে ভেরিয়েবলটি outআমার জন্য টাইপের ছিল <class 'bytes'>। স্ট্রিং হিসাবে আউটপুট পেতে আমাকে এ জাতীয় মুদ্রণের আগে ডিকোড করতে হয়েছিল:out.decode("utf-8")
PolyMesh

1
@ পার আপনি পাস করার সময় এটি আপনার পক্ষে কাজ করে না shell=True? এটা আমার জন্য কাজ করে. shlex.splitপাস করার সময় আপনার দরকার নেই shell=Trueshlex.splitশেল নন কমান্ডের জন্য। আমি মনে করি আমি এটি কিছুটা বাইরে নিয়ে যাচ্ছি কারণ এটি জলে কাঁপছে।
প্রেরক

2
পাইথন ৩.৫+ একটি কীওয়ার্ড আর্গুমেন্টকে মঞ্জুরি দেয় universal_newlines=Trueযা আপনাকে সিস্টেমের ডিফল্ট এনকোডিংয়ে ইউনিকোড স্ট্রিং প্রবেশ করতে দেয় lets ৩.7-এ এটি আরও বুদ্ধিমানের নামকরণ করা হয়েছিল text=True
ট্রিপলি

2
পাইথন ৩.6+ এর জন্য আপনি ব্যবহারের পরিবর্তে encodingপ্যারামিটার subprocess.runব্যবহার result.stdout.decode('utf-8')করতে পারেন subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8')
পিয়েরে

191

এটি সহজ উপায়, তবে কেবল ইউনিক্স (সিগউইন সহ) এবং পাইথন 2.7 এ কাজ করে।

import commands
print commands.getstatusoutput('wc -l file')

এটি (রিটার্ন_ভ্যালু, আউটপুট) দিয়ে একটি টিপল দেয়।

পাইথন 2 এবং পাইথন 3 উভয় ক্ষেত্রে কাজ করে এমন একটি সমাধানের জন্য, subprocessপরিবর্তে মডিউলটি ব্যবহার করুন:

from subprocess import Popen, PIPE
output = Popen(["date"],stdout=PIPE)
response = output.communicate()
print response

31
Subprocess.check_output ছাড়া এখন, কিন্তু খুব পুরোনো পাইথন সংস্করণের জন্য দরকারী অননুমোদিত
static_rtti

22
মনে রাখবেন এটি ইউনিক্স-নির্দিষ্ট। উদাহরণস্বরূপ এটি উইন্ডোজে ব্যর্থ হবে।
Zitrax

4
+1 আমাকে অজগর ২.৪ এর প্রাচীন সংস্করণে কাজ করতে হবে এবং এটি খুব সহায়ক ছিল
জাভাদবা

1
পাইপ ড্যুডটি কী আসে পুরো কোডটি দেখায়: সাবপ্রসেস.পিপ
কাইল

আপনি উত্তর সম্পাদনা করতে পারেন @ কেইলব্রিডেনস্টাইন
বোরিস

106

এরকম কিছু:

def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
        # returns None while subprocess is running
        retcode = p.poll() 
        line = p.stdout.readline()
        yield line
        if retcode is not None:
            break

দ্রষ্টব্য, আমি স্টাডারকে স্টডআউটে পুনঃনির্দেশ করছি, এটি আপনি যা চান ঠিক তেমনটিই নয়, তবে আমি ত্রুটির বার্তাও চাই।

এই ফাংশনটি আসার সাথে সাথে লাইনের সাথে ফলন হয় (সাধারণত আউটপুট সম্পূর্ণরূপে পেতে আপনাকে সাবপ্রসেসের জন্য অপেক্ষা করতে হবে)।

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

for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
    print line,

সম্ভাব্য অচলাবস্থা waitএবং callকার্যাবলী এড়াতে আউটপুট পেতে কোনও ধরণের সক্রিয় লুপ প্রয়োগ করতে ভুলবেন না ।
আন্দ্রে কারন

@ সিলভার হালকা: আপনার প্রক্রিয়াটি সম্ভবত ব্যবহারকারী থেকে ইনপুটটির জন্য অপেক্ষা করছে। রিটার্নের সাথে সাথে সেই ফাইলটির PIPEজন্য একটি মান সরবরাহ stdinএবং বন্ধ করার চেষ্টা করুন Popen
আন্দ্রে কারন

4
-1: এটি যদি retcodeহয় তবে একটি অসীম লুপ 0। চেক করা উচিত if retcode is not None। আপনি খালি স্ট্রিং উত্পাদ করা উচিত নয় (এমনকি একটি খালি লাইন অন্তত একটি প্রতীক '\ এন' হল): if line: yield linep.stdout.close()শেষে কল ।
jfs

2
আমি ls -l / dirname সহ কোডটি চেষ্টা করেছি এবং ডিরেক্টরিটিতে আরও অনেক ফাইল থাকা অবস্থায় দুটি ফাইল তালিকাভুক্ত করার পরে এটি ভেঙে যায়
ভ্যাসিলিস

3
@ ফুয়েনফুন্ডাচজিগ: সমস্ত আউটপুট .readlines()না পড়া পর্যন্ত ফিরে আসবে না এবং সেইজন্য এটি বড় আউটপুটটির জন্য বিরতি দেয় যা মেমরির সাথে খাপ খায় না। এছাড়াও বাফার ডেটা অনুপস্থিত এড়াতে subprocess পর থেকে প্রস্থান এর একটি এনালগ সেখানে উচিতif retcode is not None: yield from p.stdout.readlines(); break
JFS

67

ভার্টেকের উত্তর সমস্ত লাইন পড়ে না, তাই আমি একটি সংস্করণ তৈরি করেছি যা এটি করেছে:

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

ব্যবহার গ্রহণযোগ্য উত্তর হিসাবে একই:

command = 'mysqladmin create test -uroot -pmysqladmin12'.split()
for line in run_command(command):
    print(line)

6
আপনি return iter(p.stdout.readline, b'')যখন
লুপটির

2
এটি এটির একটি দুর্দান্ত ব্যবহার, এটি জানেন না! আমি কোড আপডেট করেছি।
সর্বোচ্চ একমান

আমি নিশ্চিত যে স্টাডআউট সমস্ত আউটপুট রাখে, এটি একটি বাফার সহ একটি স্ট্রিম অবজেক্ট। আমি কোনও পোপেন সম্পন্ন হওয়ার পরে অবশিষ্ট সমস্ত আউটপুট ক্ষয় করার জন্য খুব অনুরূপ কৌশল ব্যবহার করি এবং আমার ক্ষেত্রে, পোল () এবং আউটপুট লাইভও ক্যাপচারের জন্য রিডলাইন ব্যবহার করে।
সর্বোচ্চ একমান

আমি আমার বিভ্রান্তিকর মন্তব্য মুছে ফেলেছি। আমি নিশ্চিত করতে পারি, p.stdout.readline()শিশু প্রক্রিয়া ইতিমধ্যে উপস্থিত থাকলেও (খালি p.poll()না None) খালি পূর্বে-বাফার করা আউটপুটটি ফিরিয়ে আনতে পারে ।
jfs

এই কোডটি কাজ করে না। এখানে stackoverflow.com/questions/24340877/…
থ্যাং

61

এটি একটি জটিল কিন্তু অতি সহজ সমাধান যা অনেক পরিস্থিতিতে কাজ করে:

import os
os.system('sample_cmd > tmp')
print open('tmp', 'r').read()

কমান্ডের আউটপুট দিয়ে একটি অস্থায়ী ফাইল (এখানে টিএমপি হয়) তৈরি করা হয় এবং আপনি এটি থেকে আপনার পছন্দসই আউটপুটটি পড়তে পারেন।

মন্তব্যগুলি থেকে অতিরিক্ত নোট: আপনি এককালীন কাজের ক্ষেত্রে টিএমপি ফাইলটি সরাতে পারেন। আপনার যদি বেশ কয়েকবার এটি করতে হয় তবে tmp টি মুছতে হবে না।

os.remove('tmp')

5
হ্যাকি কিন্তু সুপার সিম্পল + যে কোনও জায়গায় কাজ করে .. এটি mktemp
ধারণাযুক্ত

2
সম্ভবত দ্রুততম পদ্ধতি, তবে os.remove('tmp')এটি "ফাইলহীন" করতে আরও ভাল add
XuMuK

@ XuMuK আপনি এককালীন কাজের ক্ষেত্রে ঠিক বলেছেন। যদি এটি পুনরাবৃত্ত কাজ হয় তবে মুছে ফেলা প্রয়োজন হয় না
মেহেদি সমান বুয়

1
সমাবর্তনের জন্য খারাপ, পুনরায় কাজকারীদের পক্ষে খারাপ, সিস্টেমটি যেমনটি শুরু হওয়ার আগে যেমন ছিল না তেমনি খারাপ (কোনও ক্লিনআপ নেই)
2mia

1
@ 2mia স্পষ্টতই এটি কোনও কারণে সহজ! আপনি যদি একত্রে পড়া এবং লেখার জন্য ফাইলকে এক ধরণের ভাগ করা মেমরি হিসাবে ব্যবহার করতে চান তবে এটি ভাল পছন্দ নয়। তবে, sthth এর জন্য কমান্ডের আউটপুট থাকার মতো (যেমন ls বা সন্ধান করুন বা ...) এটি একটি ভাল এবং দ্রুত পছন্দ হতে পারে। বিটিডব্লিউ যদি আপনার কোনও সাধারণ সমস্যার জন্য দ্রুত সমাধানের প্রয়োজন হয় তবে এটি আমার মনে হয় সেরা। আপনার যদি পাইপলাইন দরকার হয় তবে সাবপ্রসেসগুলি আপনার জন্য আরও দক্ষতার সাথে কাজ করে।
মেহেদী সমান বুয়

44

আমার একই সমস্যা ছিল তবে এটি করার একটি খুব সহজ উপায় খুঁজে পেয়েছি:

import subprocess
output = subprocess.getoutput("ls -l")
print(output)

আশা করি এটি সাহায্য করবে

দ্রষ্টব্য: এই দ্রবণটি পাইথন 3 নির্দিষ্ট কারণ এটি পাইথন 2 তে subprocess.getoutput()কাজ করে না


এটি কীভাবে ওপির সমস্যা সমাধান করবে? সম্প্রসারিত করুন.
রামেন শেফ

4
এটি কমান্ডের আউটপুটটিকে স্ট্রিং হিসাবে ফিরিয়ে দেয়, এর চেয়ে সহজ
আজহার 22 কে

1
অবশ্যই, মুদ্রণটি পাইথন ২-এর একটি বিবৃতি You

2
@ ডেভ মুদ্রণ (গুলি) বৈধ পাইথন ২। সাবপ্রসেস.জেটআউটপুট নয়।
ব্যবহারকারী 48956

2
বেশিরভাগ ব্যবহারের ক্ষেত্রে, সম্ভবত লোকেরা এটিই চাইবে: মনে রাখা সহজ, ফলাফলগুলি ডিকোড করতে হবে না ইত্যাদি etc. ধন্যবাদ।
bwv549

18

যে কোনও শেল কমান্ড চালাতে আপনি নিম্নলিখিত কমান্ডগুলি ব্যবহার করতে পারেন। আমি উবুন্টুতে তাদের ব্যবহার করেছি।

import os
os.popen('your command here').read()

দ্রষ্টব্য: পাইথন ২.6 থেকে এটি অবহেলা করা হয়েছে। এখন আপনার অবশ্যই ব্যবহার করা উচিত subprocess.Popen। নীচে উদাহরণ দেওয়া আছে

import subprocess

p = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")

2
সংস্করণ ২.6 থেকে হ্রাস করা হয়েছে
ফিলিপ্পো

1
@ ফিলিপোভিটেল ধন্যবাদ আমি জানতাম না যে এটি অবমূল্যায়ন করা হয়েছে।
মুহাম্মদ হাসান

1
মতে raspberrypi.stackexchange.com/questions/71547/... os.popen() পাইথন 2.6 মধ্যে নিন্দা করা হয়েছে, কিন্তু এটি করা হয় না , পাইথন 3.x উঠিয়ে যেহেতু 3.x মধ্যে এটি ব্যবহার বাস্তবায়িত হয় subprocess.Popen()
জেএল

12

আপনার মাইলেজ মে ভেরি, আমি পাইথন ২.6.৫ এ উইন্ডোজে ভার্টেকের সমাধানের জন্য @ প্রেরকের স্পিনটি চেষ্টা করেছি, তবে আমি ত্রুটি পেয়েছি এবং অন্য কোনও সমাধান কার্যকর হয়নি। আমার ত্রুটি ছিল: WindowsError: [Error 6] The handle is invalid

আমি দেখতে পেলাম যে প্রত্যাশিত আউটপুটটি ফেরত পেতে আমাকে প্রতিটি হ্যান্ডেলের পিআইপিই নির্ধারণ করতে হয়েছিল - নিম্নলিখিতটি আমার জন্য কাজ করেছিল।

import subprocess

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    return subprocess.Popen(cmd, 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE).communicate()

এবং [0]এইভাবে কল করুন ( টিউপলের প্রথম উপাদানটি পেয়েছে stdout):

run_command('tracert 11.1.0.1')[0]

আরও শিখার পরে, আমি বিশ্বাস করি যে এই পাইপ যুক্তিগুলি আমার দরকার কারণ আমি একটি কাস্টম সিস্টেমে কাজ করছি যা বিভিন্ন হ্যান্ডলগুলি ব্যবহার করে, তাই আমাকে সরাসরি সমস্ত স্ট্যান্ডের নিয়ন্ত্রণ করতে হয়েছিল।

কনসোল পপআপগুলি (উইন্ডোজ সহ) বন্ধ করতে, এটি করুন:

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    # instantiate a startupinfo obj:
    startupinfo = subprocess.STARTUPINFO()
    # set the use show window flag, might make conditional on being in Windows:
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    # pass as the startupinfo keyword argument:
    return subprocess.Popen(cmd,
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE, 
                            startupinfo=startupinfo).communicate()

run_command('tracert 11.1.0.1')

1
আকর্ষণীয় - এটি একটি উইন্ডোজ জিনিস হতে হবে। লোকেরা অনুরূপ ত্রুটি পাচ্ছে এমন ক্ষেত্রে আমি এটিকে নির্দেশ করে একটি নোট যুক্ত করব।
প্রেরক

ব্যবহার DEVNULLপরিবর্তে এর subprocess.PIPEযদি আপনি লিখুন না / একটি নল থেকে পড়তে অন্যথায় আপনি সন্তানের প্রক্রিয়া স্তব্ধ হতে পারে।
jfs

10

নিম্নলিখিত সমস্যাগুলির সাথে আমার একই সমস্যার কিছুটা আলাদা স্বাদ ছিল:

  1. STDOUT বাফারে জমা হওয়া (যেমন রিয়েলটাইমে) STDOUT বার্তাগুলি ক্যাপচার এবং রিটার্ন করুন।
    • @ ভার্টেক তার জেনারেটর ব্যবহার এবং উপরে 'ফলন'
      কীওয়ার্ড দিয়ে এই অজগরটিকে সমাধান করেছেন
  2. সমস্ত STDOUT লাইন মুদ্রণ করুন ( STDOUT বাফার পুরোপুরি পড়ার আগে প্রক্রিয়াটি প্রস্থান করা হলেও )
  3. উচ্চ-ফ্রিকোয়েন্সিতে প্রক্রিয়াটি পোলিং সিপিইউ চক্রগুলি অপচয় করবেন না
  4. সাবপ্রসেসের রিটার্ন কোডটি পরীক্ষা করুন
  5. যদি আমরা একটি শূন্য-ত্রুটি ত্রুটি রিটার্ন কোড পাই তবে STDERR মুদ্রণ করুন (STDOUT থেকে পৃথক)।

আমি নিম্নলিখিত উত্তরগুলি একত্রিত করার জন্য পূর্ববর্তী উত্তরগুলি একত্রিত করেছি এবং টুইট করেছি:

import subprocess
from time import sleep

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         shell=True)
    # Read stdout from subprocess until the buffer is empty !
    for line in iter(p.stdout.readline, b''):
        if line: # Don't print blank lines
            yield line
    # This ensures the process has completed, AND sets the 'returncode' attr
    while p.poll() is None:                                                                                                                                        
        sleep(.1) #Don't waste CPU-cycles
    # Empty STDERR buffer
    err = p.stderr.read()
    if p.returncode != 0:
       # The run_command() function is responsible for logging STDERR 
       print("Error: " + str(err))

এই কোডটি পূর্বের উত্তরগুলির মতোই কার্যকর করা হবে:

for line in run_command(cmd):
    print(line)

1
আপনার কীভাবে ঘুমের সংযোজন (.১) সিপিইউ চক্রকে অপচয় করবে না তা বোঝাতে কি আপত্তি আছে?
মোয়াতাজ এলমাস্রি

2
যদি আমরা p.poll()কলগুলির মধ্যে কোনও ঘুম না ছাড়াই কল করতে থাকি তবে আমরা এই ফাংশনটিকে কয়েকবার কল করে সিপিইউ চক্রটি নষ্ট করব। পরিবর্তে, আমরা ওএসকে জানিয়ে আমাদের লুপটি "থ্রোটল" করি যে আমাদের পরবর্তী 1/10 তম সেকেন্ডের জন্য বিরক্ত করার দরকার নেই, যাতে এটি অন্যান্য কাজগুলি সম্পাদন করতে পারে। (এটি সম্ভব যে পি.পল () খুব ঘুমায়, আমাদের ঘুমের বিবৃতিকে অপ্রয়োজনীয় করে তোলে)।
দ্য ওয়েলফিন

5

প্রাথমিক কমান্ডটি বিভক্ত subprocessকরা জটিল এবং জটিল হতে পারে।

shlex.split()নিজেকে সাহায্য করতে ব্যবহার করুন ।

নমুনা আদেশ

git log -n 5 --since "5 years ago" --until "2 year ago"

কোড

from subprocess import check_output
from shlex import split

res = check_output(split('git log -n 5 --since "5 years ago" --until "2 year ago"'))
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

shlex.split()কোড ব্যতীত নীচের মত দেখতে হবে

res = check_output([
    'git', 
    'log', 
    '-n', 
    '5', 
    '--since', 
    '5 years ago', 
    '--until', 
    '2 year ago'
])
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

1
shlex.split()একটি সুবিধা, বিশেষ করে যদি আপনি না জানেন যে শেলটিতে ঠিক কীভাবে উদ্ধৃত হওয়া কাজ করে; তবে এই স্ট্রিংটিকে ম্যানুয়ালি তালিকায় রূপান্তর করা ['git', 'log', '-n', '5', '--since', '5 years ago', '--until', '2 year ago']যদি আপনি উদ্ধৃতি বুঝতে চান তবে মোটেই কঠিন নয়।
ট্রিপলি

4

আপনার যদি একাধিক ফাইলগুলিতে শেল কমান্ড চালাতে হয় তবে এটি আমার জন্য কৌশলটি করেছে।

import os
import subprocess

# Define a function for running commands and capturing stdout line by line
# (Modified from Vartec's solution because it wasn't printing all lines)
def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

# Get all filenames in working directory
for filename in os.listdir('./'):
    # This command will be run on each file
    cmd = 'nm ' + filename

    # Run the command and capture the output line by line.
    for line in runProcess(cmd.split()):
        # Eliminate leading and trailing whitespace
        line.strip()
        # Split the output 
        output = line.split()

        # Filter the output and print relevant lines
        if len(output) > 2:
            if ((output[2] == 'set_program_name')):
                print filename
                print line

সম্পাদনা: সবেমাত্র জেএফ সেবাস্তিয়ানের পরামর্শের সাথে ম্যাক্স পার্সসনের সমাধান দেখেছি। এগিয়ে গিয়েছিলাম এবং এটি অন্তর্ভুক্ত।


Popenহয় স্ট্রিং গ্রহণ করে, তবে তারপরে আপনার প্রয়োজন shell=Trueবা আর্গুমেন্টের একটি তালিকা, যার ক্ষেত্রে ['nm', filename]স্ট্রিংয়ের পরিবর্তে আপনাকে পাস করা উচিত । দ্বিতীয়টি পছন্দনীয় কারণ শেলটি এখানে কোনও মান প্রদান না করে জটিলতা যুক্ত করে। shell=Trueস্পষ্টতই একটি স্ট্রিং পাস করা উইন্ডোজে কাজ করার জন্য ঘটেছিল, তবে এটি পরবর্তী কোনও পাইথন সংস্করণে পরিবর্তিত হতে পারে।
ট্রিপলি

2

@ সেন্ডারেলের মতে, আপনি যদি আমার মতো পাইথন ৩..6 ব্যবহার করেন:

def sh(cmd, input=""):
    rst = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8"))
    assert rst.returncode == 0, rst.stderr.decode("utf-8")
    return rst.stdout.decode("utf-8")
sh("ls -a")

আপনি ঠিক কমান্ড চালানোর মতো কাজ করবেন ash


আপনি কীওয়ার্ড আর্গুমেন্ট পুনরায় উদ্ভাবন করছেন check=True, universal_newlines=True। অন্য কথায় subprocess.run()ইতিমধ্যে আপনার কোড যা করে সবকিছু করে।
ট্রিপলি

1

আপনি যদি subprocessপাইথন মডিউলটি ব্যবহার করেন তবে আপনি STDOUT, STDERR এবং কমান্ড কোড পৃথকভাবে পরিচালনা করতে পারবেন। সম্পূর্ণ কমান্ড কলার বাস্তবায়নের জন্য আপনি একটি উদাহরণ দেখতে পাচ্ছেন। আপনি চাইলে অবশ্যই এর সাথে প্রসারিত try..exceptকরতে পারেন।

নীচের ফাংশনটি STDOUT, STDERR এবং রিটার্ন কোড দেয় যাতে আপনি এগুলি অন্য স্ক্রিপ্টে পরিচালনা করতে পারেন।

import subprocess

def command_caller(command=None)
    sp = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
    out, err = sp.communicate()
    if sp.returncode:
        print(
            "Return code: %(ret_code)s Error message: %(err_msg)s"
            % {"ret_code": sp.returncode, "err_msg": err}
            )
    return sp.returncode, out, err

এর আরেকটি দুর্বল পুনর্নির্মাণ subprocess.run()। চাকা পুনরুদ্ধার করবেন না।
ট্রিপলি

0

উদাহরণস্বরূপ, চালানো ('ls -ahl') তিন / চারটি সম্ভাব্য রিটার্ন এবং ওএস প্ল্যাটফর্মের পার্থক্যযুক্ত:

  1. কোনও আউটপুট না, তবে সফলভাবে চালান
  2. খালি লাইন আউটপুট আউট, সফলভাবে চালান
  3. রান ব্যর্থ হয়েছে
  4. আউটপুট কিছু, সফলভাবে চালান

নীচে ফাংশন

def execute(cmd, output=True, DEBUG_MODE=False):
"""Executes a bash command.
(cmd, output=True)
output: whether print shell output to screen, only affects screen display, does not affect returned values
return: ...regardless of output=True/False...
        returns shell output as a list with each elment is a line of string (whitespace stripped both sides) from output
        could be 
        [], ie, len()=0 --> no output;    
        [''] --> output empty line;     
        None --> error occured, see below

        if error ocurs, returns None (ie, is None), print out the error message to screen
"""
if not DEBUG_MODE:
    print "Command: " + cmd

    # https://stackoverflow.com/a/40139101/2292993
    def _execute_cmd(cmd):
        if os.name == 'nt' or platform.system() == 'Windows':
            # set stdin, out, err all to PIPE to get results (other than None) after run the Popen() instance
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        else:
            # Use bash; the default is sh
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable="/bin/bash")

        # the Popen() instance starts running once instantiated (??)
        # additionally, communicate(), or poll() and wait process to terminate
        # communicate() accepts optional input as stdin to the pipe (requires setting stdin=subprocess.PIPE above), return out, err as tuple
        # if communicate(), the results are buffered in memory

        # Read stdout from subprocess until the buffer is empty !
        # if error occurs, the stdout is '', which means the below loop is essentially skipped
        # A prefix of 'b' or 'B' is ignored in Python 2; 
        # it indicates that the literal should become a bytes literal in Python 3 
        # (e.g. when code is automatically converted with 2to3).
        # return iter(p.stdout.readline, b'')
        for line in iter(p.stdout.readline, b''):
            # # Windows has \r\n, Unix has \n, Old mac has \r
            # if line not in ['','\n','\r','\r\n']: # Don't print blank lines
                yield line
        while p.poll() is None:                                                                                                                                        
            sleep(.1) #Don't waste CPU-cycles
        # Empty STDERR buffer
        err = p.stderr.read()
        if p.returncode != 0:
            # responsible for logging STDERR 
            print("Error: " + str(err))
            yield None

    out = []
    for line in _execute_cmd(cmd):
        # error did not occur earlier
        if line is not None:
            # trailing comma to avoid a newline (by print itself) being printed
            if output: print line,
            out.append(line.strip())
        else:
            # error occured earlier
            out = None
    return out
else:
    print "Simulation! The command is " + cmd
    print ""

0

আউটপুটটি একটি পাঠ্য ফাইলে পুনর্নির্দেশ করা যায় এবং তারপরে এটি আবার পড়তে পারে।

import subprocess
import os
import tempfile

def execute_to_file(command):
    """
    This function execute the command
    and pass its output to a tempfile then read it back
    It is usefull for process that deploy child process
    """
    temp_file = tempfile.NamedTemporaryFile(delete=False)
    temp_file.close()
    path = temp_file.name
    command = command + " > " + path
    proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
    if proc.stderr:
        # if command failed return
        os.unlink(path)
        return
    with open(path, 'r') as f:
        data = f.read()
    os.unlink(path)
    return data

if __name__ == "__main__":
    path = "Somepath"
    command = 'ecls.exe /files ' + path
    print(execute(command))

অবশ্যই এটি করতে পারে তবে আপনি কেন চাইবেন; এবং কেন আপনি পাসের পরিবর্তে শেলটি ব্যবহার করবেন stdout=temp_file?
ট্রিপলি

প্রকৃতপক্ষে, সাধারণভাবে আপনি ঠিক বলেছেন তবে আমার উদাহরণে ecls.exeমনে হয় অন্য কমান্ড লাইন সরঞ্জাম স্থাপন করা হয়েছে, তাই সহজ উপায়টি কখনও কখনও কাজ করে না।
মিঃ

0

কার্ল ব্যবহার করে এটি করার জন্য একটি ছোট বাশ স্ক্রিপ্ট লিখেছিলেন

https://gist.github.com/harish2704/bfb8abece94893c53ce344548ead8ba5

#!/usr/bin/env bash

# Usage: gdrive_dl.sh <url>

urlBase='https://drive.google.com'
fCookie=tmpcookies

curl="curl -L -b $fCookie -c $fCookie"
confirm(){
    $curl "$1" | grep jfk-button-action | sed -e 's/.*jfk-button-action" href="\(\S*\)".*/\1/' -e 's/\&amp;/\&/g'
}

$curl -O -J "${urlBase}$(confirm $1)"
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.