python - শেল কমান্ড চালানো এবং আউটপুট capturing




shell subprocess (10)

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

একটি কোড উদাহরণ কি এমন একটি কাজ করবে?

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

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'

আধুনিক পাইথন সমাধান (> = 3.1):

 res = subprocess.check_output(lcmd, stderr=subprocess.STDOUT)

আপনার মাইলেজ মে ভেরি, আমি পাইথন 2.6.5 এর উইন্ডোতে উইন্ডোতে ওয়ার্টেকের সমাধানটি প্রেরণকারীর স্পিনের চেষ্টা করেছি, কিন্তু আমি ত্রুটিগুলি পেয়েছিলাম এবং অন্য কোনো সমাধান কাজ করে নি। আমার ত্রুটি ছিল: 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')

আমি একই সমস্যা ছিল কিন্তু এই অনুসরণ এই খুব সহজ উপায় figured

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

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

দ্রষ্টব্য: এই সমাধানটি python3 নির্দিষ্ট হিসাবে subprocess.getoutput() পাইথন 2 এ কাজ করে না


উদাহরণস্বরূপ, চালান ('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://.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 ""

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

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

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

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

os.remove('tmp')

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

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

এটি একটি tuple ফেরত দেয় (return_value, আউটপুট)

এটি শুধুমাত্র python2.7 কাজ করে: এটি python3 উপলব্ধ নয়। একটি সমাধান যা উভয় ক্ষেত্রেই কাজ করে, তার পরিবর্তে subprocess মডিউলটি ব্যবহার করুন:

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

পাইথন 3.5:

import subprocess

output = subprocess.run("ls -l", shell=True, stdout=subprocess.PIPE, 
                        universal_newlines=True)
print(output.stdout)

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

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

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


নিম্নোক্ত প্রয়োজনীয়তাগুলির সাথে একই সমস্যাটির সামান্য ভিন্ন স্বাদ ছিল:

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

আমি মিলিত করেছি এবং নীচের উত্তরগুলির সাথে পূর্ববর্তী উত্তরগুলি tweaked করেছি:

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)

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

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)




subprocess