subprocess.Popen 是 Python 中用于执行外部命令或程序的模块之一。它提供了创建子进程并与之交互的灵活方式。以向 subprocess.Popen 传递一个命令字符串或命令列表,它将调用操作系统的 shell 来执行该命令。
项目中需要在 Python 的代码中执行一些系统指令,例如调用项目中的某个可执行程序,所以就使用了 subprocess.Popen 方法。
源代码如下:
def subprocess_popen_cmd(cmds, cwd=None):
if isinstance(cmds, list):
cmds = " ".join(cmds)
p = subprocess.Popen(
cmds,
stdout=subprocess.PIPE,
shell=True,
executable="/bin/bash",
stderr=subprocess.STDOUT,
universal_newlines=True,
cwd=cwd,
)
logging.info("subprocess_popen_cmd start. pid:%d cmds:%r", p.pid, cmds)
while p.poll() is None:
data = p.stdout.readline()
data = data.strip()
if data:
logging.info(data)
logging.info(
"subprocess_popen_cmd end. pid:%d, returncode:%d cmds:%r",
p.pid,
p.returncode,
cmds,
)
if p.returncode != 0:
raise Exception(f"subprocess_popen_cmd had error!{cmds}")
这段代码是一个 Python 函数,用于执行外部命令并捕获其输出。接收传入的系统命令,使用 subprocess.Popen 函数创建子进程来执行指定的命令。设置了一些参数来配置子进程的执行环境,具体包括:
stdout=subprocess.PIPE:将子进程的标准输出连接到管道,以便后续读取输出。
shell=True:表示通过系统的 shell 来执行命令,可以使用命令的通配符、管道等功能。
executable="/bin/bash":指定要执行的 shell 程序,这里是 /bin/bash。
stderr=subprocess.STDOUT:将子进程的标准错误输出合并到标准输出中。
universal_newlines=True:将输入和输出转换为文本模式,而不是字节模式。
cwd=cwd:设置子进程的工作目录。
如果调用的shell命令本身在执行之后会突然出现很多输出,则这个时候可能会导致hang在那里,表现就是卡死了,程序也不往下走,也不会报错。。。
原因就是:PIPE本身可容纳的量比较小,所以程序会卡死,所以一大堆内容输出过来的时候,会导致PIPE不足够处理这些内容
实际我的业务需求并不关心程序执行过程中的输出,只要知道最后的执行结果即可,使用上面的 subprocess.Popen 有些冗余,所以我改成了使用 subprocess.run 。修改后的代码:
def subprocess_popen_cmd(cmds, cwd=None):
if isinstance(cmds, list):
cmds = " ".join(cmds)
print("cmds---subprocess.ru---", cmds)
try:
subprocess.run(
cmds,
shell=True,
executable="/bin/bash",
check=True,
cwd=cwd # 指定子进程的工作目录
)
except subprocess.CalledProcessError as e:
raise Exception(f"Error executing cmd: {cmds}\n{e.stderr.decode('utf-8')}")
subprocess.Popen 和 subprocess.run 是 Python 中用于执行外部命令的两个常用函数,它们之间有几个重要的区别:
subprocess.Popen 是一个更底层的接口,允许你以更灵活的方式创建子进程并与之交互。它返回一个 Popen 对象,通过该对象你可以控制子进程的输入、输出和状态。
subprocess.run 是一个更高级别的函数,封装了一系列常用的子进程操作,例如执行命令并等待其完成,然后返回一个包含执行结果的 CompletedProcess 对象。
subprocess.Popen 提供了更多的灵活性,但需要你手动管理子进程的输入、输出和状态,因此在处理更复杂的子进程交互时可能需要更多的工作。综上所述,subprocess.run 适合简单地执行外部命令并获取输出;subprocess.Popen 适合更灵活地控制子进程,以及处理更复杂的子进程交互,注意不要使用 stdout=subprocess.PIPE 。
本文分享自 pythonista的日常 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!