本文共 14311 字,大约阅读时间需要 47 分钟。
我想编写一个函数,该函数将执行命令并以字符串形式返回其输出,无论它是错误消息还是成功消息。 我只想获得与命令行相同的结果。
能做到这一点的代码示例是什么?
例如:
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'
答案无法读取所有行,因此我制作了一个可以读取的版本:
def run_command(command): p = .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)
您的里程可能会有所不同,我尝试使用@senderle在Windows 2.6.5上的Windows中使用Vartec的解决方案,但是我遇到了错误,并且没有其他解决方案起作用。 我的错误是: WindowsError: [Error 6] The handle is invalid
。
我发现我必须为每个句柄分配PIPE才能使其返回我期望的输出-以下内容对我有用。
import subprocessdef 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]
学习更多之后,我相信我需要这些管道参数,因为我正在使用不同句柄的自定义系统上工作,因此必须直接控制所有std。
要停止控制台弹出窗口(在Windows中),请执行以下操作:
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')
如果您需要在多个文件上运行一个shell命令,那么这对我就成功了。
import osimport 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 directoryfor 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
编辑:刚刚看到了JF Sebastian的建议的Max Persson的解决方案。 继续前进,并纳入。
这是一个棘手但超级简单的解决方案,可在许多情况下使用:
import osos.system('sample_cmd > tmp')print open('tmp', 'r').read()
使用命令的输出创建一个临时文件(这里是tmp),您可以从中读取所需的输出。
注释中的额外说明:如果是一次性作业,则可以删除tmp文件。 如果您需要多次执行此操作,则无需删除tmp。
os.remove('tmp')
对于以下问题,我对同一问题的口味略有不同:
我结合并调整了先前的答案,以得出以下结论:
import subprocessfrom time import sleepdef 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)
我遇到了同样的问题,但是想出了一种非常简单的方法:
import subprocessoutput = subprocess.getoutput("ls -l")print(output)
希望能帮上忙
注意:此解决方案特定于Python3,因为subprocess.getoutput subprocess.getoutput()
在Python2中不起作用
您可以使用以下命令来运行任何shell命令。 我在ubuntu上使用过它们。
import osos.popen('your command here').read()
注意:自python 2.6起不推荐使用。 现在,您必须使用subprocess.Popen
。 以下是示例
import subprocessp = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]print p.split("\n")
例如,execute('ls -ahl')区分了三种/四种可能的收益和OS平台:
功能如下
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 valuesreturn: ...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 outelse: print "Simulation! The command is " + cmd print ""
像这样:
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
请注意,我正在将stderr重定向到stdout,它可能并非您想要的,但我也想要错误消息。
此函数逐行产生 (通常,您必须等待子进程完成才能获得整体输出)。
对于您的情况,用法是:
for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()): print line,
这个问题的答案取决于您使用的Python版本。 最简单的方法是使用函数:
>>> 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命令,请参阅此答案末尾关于shell=True
的注释。
check_output
函数可用于几乎所有仍在广泛使用的Python版本(2.7+)。 2但对于较新的版本,不再推荐使用此方法。
run
如果您使用的是Python 3.5或更高版本,并且不需要向后兼容 ,则建议使用 。 它为subprocess
模块提供了非常通用的高级API。 要捕获程序的输出,请将subprocess.PIPE
标志传递给stdout
关键字参数。 然后访问返回的对象的stdout
属性:
>>> import subprocess>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)>>> result.stdoutb'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
返回值是一个bytes
对象,因此,如果要使用正确的字符串,则需要对其进行decode
。 假设被调用的进程返回一个UTF-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
来运行更复杂的Shell命令,如下面的注释所述。
与旧的处理方式相比,这仅增加了一点复杂性。 但是我认为值得这样做:现在,您run
功能就可以完成几乎所有需要做的事情。
check_output
如果您使用的是旧版本的Python,或者需要适度的向后兼容性,则可以使用如上文所述的check_output
函数。 自python 2.7开始提供。
subprocess.check_output(*popenargs, **kwargs)
它采用与Popen
相同的参数(请参见下文),并返回一个包含程序输出的字符串。 该答案的开头有一个更详细的用法示例。 在Python 3.5及更高版本中, check_output
等效于使用check=True
和stdout=PIPE
执行run
,并仅返回stdout
属性。
您可以传递stderr=subprocess.STDOUT
以确保错误消息包含在返回的输出中-但是在某些版本的Python中,将stderr=subprocess.PIPE
check_output
传递给check_output
可能导致 。 如果不考虑安全性,您还可以通过传递shell=True
来运行更复杂的Shell命令,如下面的注释所述。
如果您需要从stderr
进行管道传输或将输入传递给进程,则check_output
将无法完成任务。 在这种情况下,请参见下面的Popen
示例。
Popen
如果需要深度向后兼容性,或者需要比check_output
提供的功能更复杂的功能,则必须直接使用Popen
对象,该对象封装了用于子流程的低级API。
Popen
构造函数可以接受不带参数的单个命令 ,也可以接受包含命令的列表作为其第一项,后跟任意数量的参数,每个参数均作为列表中的单独项。 可以帮助将字符串解析为适当格式的列表。 Popen
对象还接受用于进程IO管理和低级配置的 。
要发送输入和捕获输出, 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 outfoofoo
注意 ,它表明在某些系统上,您可能需要将stdout
, stderr
和stdin
全部设置为PIPE
(或DEVNULL
)才能使communicate
正常工作。
在极少数情况下,您可能需要复杂的实时输出捕获。 的答案提出了一条前进的道路,但如果 ,则communicate
以外的方法很容易陷入僵局。
与上述所有功能一样,当不考虑安全性时,可以通过传递shell=True
来运行更复杂的Shell命令。
1.运行shell命令: shell=True
参数
通常情况下,每次调用run
, check_output
,或Popen
构造函数执行一个程序 。 这意味着没有花哨的bash风格的管道。 如果要运行复杂的Shell命令,则可以传递shell=True
,这三个功能都支持。
但是,这样做会引起 。 如果您除了做轻量级脚本编写外,还不如分别调用每个进程,并将每个进程的输出作为输入通过
run(cmd, [stdout=etc...], input=other_output)
要么
Popen(cmd, [stdout=etc...]).communicate(other_output)
直接连接管道的诱惑力很强; 抵抗它。 否则,您很可能会遇到僵局,或者不得不做类似骇人听闻的事情。
2. Unicode注意事项
check_output
在Python 2中返回一个字符串,但在Python 3中返回一个bytes
对象。如果您还没有时间那么值得花一点时间。
为subprocess
拆分初始命令可能很棘手且麻烦。
使用shlex.split()
帮助自己。
样例命令
git log -n 5 --since "5 years ago" --until "2 year ago"
编码
from subprocess import check_outputfrom shlex import splitres = 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...'
根据@senderle,如果您像我一样使用python3.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")
就像您在bash中运行命令一样
如果使用subprocess
python模块,则可以分别处理STDOUT,STDERR和命令的返回代码。 您可以看到完整的命令调用程序实现的示例。 当然,您可以使用try..except
扩展它, try..except
需要。
下面的函数返回STDOUT,STDERR和Return代码,因此您可以在其他脚本中处理它们。
import subprocessdef 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
可以将输出重定向到文本文件,然后将其读回。
import subprocessimport osimport tempfiledef 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 dataif __name__ == "__main__": path = "Somepath" command = 'ecls.exe /files ' + path print(execute(command))
这很容易,但仅适用于Unix(包括Cygwin)和Python2.7。
import commandsprint commands.getstatusoutput('wc -l file')
它返回带有(return_value,output)的元组。
对于在这两个Python2和Python3有效的解决方案,使用subprocess
模块来代替:
from subprocess import Popen, PIPEoutput = Popen(["date"],stdout=PIPE)response = output.communicate()print response
转载地址:http://ovdnb.baihongyu.com/