你可以参考以下代码示例:
例如:
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(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'
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 命令,请参阅本答案末尾关于 shell=True
的注释。
check_output
函数适用于所有官方维护版本的 Python。但是,对于较新版本,有一种更灵活的方法可供选择。
run
如果您使用的是 Python 3.5+,并且不需要向后兼容,则官方文档推荐使用新的 run
函数来完成大多数任务。它为 subprocess
模块提供了非常通用的高级 API。要捕获程序的输出,请将 subprocess.PIPE
标志传递给 stdout
关键字参数。然后访问返回的 CompletedProcess
对象的 stdout
属性:
>>> 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
操作。假设被调用的进程返回一个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']
>>> ip = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=ip)
>>> result.stdout.decode('utf-8')
'foofoo\n'
stderr=subprocess.PIPE
(将输出捕获到 result.stderr
)或 stderr=subprocess.STDOUT
(将输出与常规输出一起捕获到 result.stdout
)来捕获错误。如果希望在进程返回非零退出代码时抛出异常,可以传递 check=True
。(或者可以检查上面的result
的returncode
属性。) 当安全性不是问题时,也可以通过传递shell=True
来运行更复杂的shell命令,如本答案末尾所述。>>> subprocess.run(['ls', '-l'], capture_output=True, text=True).stdout
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
使用这种方式的run
相比旧方法稍微复杂了一点。但是现在你可以只用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
来确保错误消息包含在返回的输出中。当安全性不是问题时,您还可以通过传递 shell=True
来运行更复杂的 shell 命令,如本答案末尾所述。stderr
进行管道传输或向进程传递输入,则 check_output
将无法胜任。在这种情况下,请参见下面的 Popen
示例。
Popen
check_output
或 run
提供的更复杂的功能,则必须直接使用 Popen
对象,该对象封装了子进程的低级 API。
Popen
构造函数接受一个不带参数的单个命令,或者包含一个命令作为其第一项的列表,后跟任意数量的参数,每个参数作为列表中的单独项。shlex.split
可以帮助将字符串解析为适当格式的列表。 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 out
foofoo
请注意 Aaron Hall的回答,它表明在某些系统上,您可能需要将stdout
,stderr
和stdin
全部设置为PIPE
(或DEVNULL
),才能使communicate
正常工作。
在一些罕见情况下,您可能需要进行复杂的实时输出捕获。Vartec的回答提供了一种前进的方法,但是除communicate
之外的其他方法如果使用不当可能会出现死锁。
与所有上述功能一样,当安全性不成问题时,可以通过传递shell=True
来运行更复杂的shell命令。
1. 运行shell命令:参数shell=True
通常,每次调用run
、check_output
或Popen
构造函数都会执行单个程序。这意味着没有花哨的bash风格的管道。如果要运行复杂的shell命令,可以传递shell=True
,这三个函数都支持。例如:
>>> subprocess.check_output('cat books/* | wc', shell=True, text=True)
' 1299377 17005208 101299376\n'
然而,这样做会引发安全问题。如果你要做的不仅仅是轻量级脚本编程,最好分别调用每个进程,并将每个进程的输出作为下一个进程的输入传递,通过
run(cmd, [stdout=etc...], input=other_output)
或者
Popen(cmd, [stdout=etc...]).communicate(other_output)
直接连接管道的诱惑很强,要抵制它。否则,您可能会遇到死锁或不得不使用this等hacky方法。
check_output()
和communicate()
,您必须等待进程完成,而使用poll()
,则可以实时获取输出。这取决于您的需求。 - vartecout
的类型是<class 'bytes'>
。为了将输出作为字符串获取,我必须在打印之前进行解码,如下所示:
out.decode("utf-8")
- PolyMeshshell=True
与其一起运行,但更有效和优雅的解决方案是在Python中仅作为子进程运行ps
并进行过滤。(如果您决定将其保留在shell中,您确实应该重构那些重复的grep
。) - tripleeesubprocess.check_output('cat books/* | wc', shell=True, text=True)
的功能,如果您能将其放在帖子顶部,那将非常有帮助。 - Digio这种方法更加简单,但仅适用于Unix系统(包括Cygwin)和Python2.7。
import commands
print commands.getstatusoutput('wc -l file')
它返回一个包含(返回值、输出)的元组。from subprocess import Popen, PIPE
output = Popen(["date"],stdout=PIPE)
response = output.communicate()
print response
python3
提供了 subprocess.getoutput()
:
import subprocess
output = subprocess.getoutput("ls -l")
print(output)
subprocess.check_output
相比没有任何优势,除了少几个字符外,但考虑到缺点,这应该几乎不会影响你的决策。 - tripleeefor line in output.splitlines(): print(line)
或者单词:for word in output.split(): print(word)
- Celuk类似于这样:
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,
retcode
是0,这是一个无限循环。应该检查if retcode is not None
。不应该生成空字符串(即使是空行也至少有一个符号\n
):if line: yield line
。在结束时调用p.stdout.close()
。 - jfsiter(p.stdout.readline, b'')
,而无需使用while循环。 - jfs.readlines()
方法会等到所有的输出被读取才返回,因此对于不能全部存入内存的大量输出它就会出问题。为了避免子进程退出后丢失缓冲数据,应该添加类似于if retcode is not None: yield from p.stdout.readlines(); break
的代码。 - jfs这是一个棘手但又非常简单的解决方案,适用于许多情况:
import os
os.system('sample_cmd > tmp')
print(open('tmp', 'r').read())
使用命令的输出创建一个临时文件(tmp),您可以从中读取所需的输出内容。
来自评论的额外说明:如果是一次性任务,您可以删除tmp文件。如果需要多次执行此操作,则无需删除tmp文件。
os.remove('tmp')
os.remove('tmp')
以使其“无文件”。 - XuMuKVartec的答案没有读取所有行,所以我做了一个版本来实现:
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)
return iter(p.stdout.readline, b'')
替代 while 循环。 - jfsp.poll()
不是 None
),p.stdout.readline()
可能会返回先前缓冲的非空输出。 - jfsshell=False
,因此您应将命令作为列表传递(而不是字符串)。我已更新答案以添加缺失的.split()
。 - jfs您可以使用以下命令来运行任何Shell命令。我已经在Ubuntu上使用过它们。
import os
os.popen('your command here').read()
注意:自 Python 2.6 起,此功能已被弃用。现在您必须使用 subprocess.Popen
。以下是示例:
import subprocess
p = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")
subprocess.check_output
和类似的工具可以处理的简单任务,您也要避免使用subprocess.Popen
。后者在处理非平凡命令时存在多个漏洞。 - tripleeeprint
不是一个命令。你是不是想说 print()
? - rokejulianlockhart对于Python 3.7+,使用subprocess.run
并传递capture_output=True
:
import subprocess
result = subprocess.run(['echo', 'hello', 'world'], capture_output=True)
print(repr(result.stdout))
这将返回字节:
b'hello world\n'
如果您希望将字节转换为字符串,请加上text=True
:result = subprocess.run(['echo', 'hello', 'world'], capture_output=True, text=True)
print(repr(result.stdout))
这将使用您的默认编码读取字节:
'hello world\n'
如果您需要手动指定不同的编码,请使用encoding="your encoding"
而不是text=True
:
result = subprocess.run(['echo', 'hello', 'world'], capture_output=True, encoding="utf8")
print(repr(result.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)
p.poll()
之间没有任何休眠,那么我们将浪费数百万次调用此函数的CPU周期。相反,我们通过告诉操作系统我们在接下来的1/10秒内不需要被打扰,以便它可以执行其他任务来“节流”我们的循环。(可能p.poll()也会睡眠,使我们的睡眠语句变得多余)。 - The Aelfinn你的结果可能会有所不同,我尝试了 @senderle 对 Vartec 的解决方法在 Python 2.6.5 上的 Windows 版本,但是我一直在遇到错误,并且没有其他解决方案可行。我的错误是:WindowsError: [Error 6] The handle is invalid
。
我发现我必须为每个句柄分配 PIPE 才能得到我期望的输出 - 以下是对我有效的方法。
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]
经过更多学习,我相信我需要这些管道参数,因为我正在使用不同的句柄的自定义系统,所以我必须直接控制所有的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')
DEVNULL
代替subprocess.PIPE
,否则可能会挂起子进程。 - jfs
os.system
,如果这是你真正的问题。 - tripleee