在Python编程中,经常需要执行外部命令或程序以完成特定任务,比如文件操作、系统监控、自动化测试等。Python提供了几种方式来实现这一需求,包括使用标准库中的subprocess
模块、os
模块中的部分函数,以及更高级的第三方库如sh
、pexpect
等。本章节将重点介绍如何使用subprocess
模块在Python程序中运行命令,因为它提供了最灵活和强大的方式来处理外部命令的执行。
subprocess
模块允许你启动新的进程,连接到它们的输入/输出/错误管道,并获取它们的返回码。这是Python执行外部命令的推荐方式,因为它比使用os.system()
或os.popen()
等旧方法更加安全和灵活。
subprocess
模块中的几个常用函数包括:
subprocess.run()
(Python 3.5+):推荐用于新的代码,它是一个高级接口,用于执行命令并等待完成。subprocess.Popen()
:一个更底层的接口,提供了更多的灵活性,比如可以非阻塞地执行命令。subprocess.call()
、subprocess.check_call()
、subprocess.check_output()
:这些函数是subprocess.run()
的前身,虽然在新代码中推荐使用subprocess.run()
,但在一些旧代码中仍然可以看到它们的身影。subprocess.run()
函数是Python 3.5及以后版本中引入的,用于替代subprocess.call()
、subprocess.check_call()
和subprocess.check_output()
。它提供了一个简洁的接口来执行外部命令并获取其输出。
基本用法:
import subprocess
# 执行命令并等待完成
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
# 检查命令是否成功执行
if result.returncode == 0:
print("命令执行成功,输出如下:")
print(result.stdout)
else:
print("命令执行失败,错误信息如下:")
print(result.stderr)
在这个例子中,subprocess.run()
执行了ls -l
命令(在Unix/Linux系统中列出当前目录下的文件和文件夹的详细信息),capture_output=True
参数用于捕获命令的标准输出和标准错误输出,text=True
参数(在Python 3.7+中引入)确保输出以文本形式返回,而不是字节串。
参数说明:
args
:要执行的命令和参数,应作为列表传递,例如['ls', '-l']
。capture_output
:是否捕获命令的输出,默认为False
。text
:是否在捕获输出时以文本模式打开文件(Python 3.7+),默认为False
(即以字节模式打开)。shell
:是否通过shell来执行命令(如/bin/sh -c
),默认为False
。使用shell=True
时要小心注入攻击。timeout
:命令执行的最大时间(秒),如果命令超时,将抛出subprocess.TimeoutExpired
异常。如果你需要更复杂的控制,比如同时执行多个命令、非阻塞地执行命令或处理大量的输入输出数据,那么subprocess.Popen()
可能是更好的选择。
基本用法:
import subprocess
# 创建Popen对象
proc = subprocess.Popen(['grep', 'python'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
# 向命令发送输入数据
stdout, stderr = proc.communicate(input='Python is awesome!\nPython is fun!\n')
# 检查命令是否成功执行
if proc.returncode == 0:
print("命令执行成功,输出如下:")
print(stdout)
else:
print("命令执行失败,错误信息如下:")
print(stderr)
在这个例子中,subprocess.Popen()
被用来执行grep
命令,它搜索输入中包含“python”的行。stdin
、stdout
和stderr
参数分别用于指定子进程的标准输入、标准输出和标准错误输出的处理方式。communicate()
方法用于向子进程发送数据并等待其完成,同时获取输出和错误信息。
注意:
Popen
时,应始终调用communicate()
方法来发送数据和获取输出,这样可以避免死锁等问题。stdin
、stdout
、stderr
设置为None
或subprocess.DEVNULL
(Python 3.3+)。shell=True
或构造包含外部输入的命令时,要特别小心注入攻击。尽量使用列表形式传递命令和参数,避免使用字符串拼接。通过subprocess
模块,Python程序能够灵活且安全地执行外部命令。subprocess.run()
和subprocess.Popen()
是执行外部命令的两种主要方式,它们各自适用于不同的场景。掌握这些技能将极大地增强你的Python脚本编写能力,使其能够完成更加复杂和自动化的任务。在编写涉及外部命令的Python脚本时,请务必注意安全性、错误处理和跨平台兼容性。