浅谈Python3中subprocess.Popen与os.popen的区别
程序员文章站
2024-02-23 19:36:04
...
之前遇到一个使用os.popen时想屏蔽控制台的stderr打印的问题,在研究这个问题的时候,对os.popen稍微打卡看了下,发现popen其实只是对subprocess.Popen的封装,先把源码粘出来:
def popen(cmd, mode="r", buffering=-1):
if not isinstance(cmd, str):
raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
if mode not in ("r", "w"):
raise ValueError("invalid mode %r" % mode)
if buffering == 0 or buffering is None:
raise ValueError("popen() does not support unbuffered streams")
import subprocess, io
if mode == "r":
proc = subprocess.Popen(cmd,
shell=True,
stdout=subprocess.PIPE,
bufsize=buffering)
return _wrap_close(io.TextIOWrapper(proc.stdout), proc)
else:
proc = subprocess.Popen(cmd,
shell=True,
stdin=subprocess.PIPE,
bufsize=buffering)
return _wrap_close(io.TextIOWrapper(proc.stdin), proc)
可以看到,popen的逻辑很简单,通过入参mode来判断是往控制台写还是从控制台读,然后确定传入stdout还是stdin参数调用subprocess.Popen;最后对返回值使用io.TextIOWrapper进行封装返回
所以os.popen相比subprocess.Popen存在两个问题:
1、不能对标准输入输出外的内容进行处理,这点在我之前写的帖子中已经有解释了,可以参考https://blog.csdn.net/Ls4034/article/details/89161157
2、多线程调用,当你需要对系统下达一套“组合拳”命令时,每次放出的招式可能不是一样的,举例说明:
# -*- coding: utf-8 -*-
import os
if __name__ == '__main__':
CMD_1 = "adb -H 1.2.3.1 devices" # ip未知,执行肯定会报错
CMD_2 = "adb -H 1.2.3.2 devices" # ip未知,执行肯定会报错
CMD_3 = "adb -H 1.2.3.3 devices" # ip未知,执行肯定会报错
CMD_4 = "adb -H 1.2.3.4 devices" # ip未知,执行肯定会报错
os.popen(CMD_1, mode="r", buffering=-1)
os.popen(CMD_2, mode="r", buffering=-1)
os.popen(CMD_3, mode="r", buffering=-1)
os.popen(CMD_4, mode="r", buffering=-1)
执行结果如下:
** Cannot start server on remote host
error: can't connect to 1.2.3.1:7305: cannot connect to 1.2.3.1:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)
** Cannot start server on remote host
error: can't connect to 1.2.3.3:7305: cannot connect to 1.2.3.3:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)
** Cannot start server on remote host
error: can't connect to 1.2.3.2:7305: cannot connect to 1.2.3.2:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)
** Cannot start server on remote host
error: can't connect to 1.2.3.4:7305: cannot connect to 1.2.3.4:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)
可以看到执行顺序并不是有序的,同理,如果只是调用subprocess.Popen结果也是一样的,但是subprocess.Popen有更灵活的方式:
# -*- coding: utf-8 -*-
import subprocess
if __name__ == '__main__':
CMD_1 = "adb -H 1.2.3.1 devices" # ip未知,执行肯定会报错
CMD_2 = "adb -H 1.2.3.2 devices" # ip未知,执行肯定会报错
CMD_3 = "adb -H 1.2.3.3 devices" # ip未知,执行肯定会报错
CMD_4 = "adb -H 1.2.3.4 devices" # ip未知,执行肯定会报错
proc_1 = subprocess.Popen(CMD_1, shell=True, stdout=subprocess.PIPE, bufsize=-1)
proc_1.wait()
proc_2 = subprocess.Popen(CMD_2, shell=True, stdout=subprocess.PIPE, bufsize=-1)
proc_2.wait()
proc_3 = subprocess.Popen(CMD_3, shell=True, stdout=subprocess.PIPE, bufsize=-1)
proc_3.wait()
proc_4 = subprocess.Popen(CMD_4, shell=True, stdout=subprocess.PIPE, bufsize=-1)
proc_4.wait()
执行代码,输出的顺序就不会乱序了,但是,执行效率会受一定影响,需要酌情使用
** Cannot start server on remote host
error: can't connect to 1.2.3.1:7305: cannot connect to 1.2.3.1:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)
** Cannot start server on remote host
error: can't connect to 1.2.3.2:7305: cannot connect to 1.2.3.2:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)
** Cannot start server on remote host
error: can't connect to 1.2.3.3:7305: cannot connect to 1.2.3.3:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)
** Cannot start server on remote host
error: can't connect to 1.2.3.4:7305: cannot connect to 1.2.3.4:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)
上一篇: python 处理电子表格
推荐阅读
-
python中os.system、os.popen和subprocess.popen的区别
-
浅谈Python3中subprocess.Popen与os.popen的区别
-
浅谈php中global与$GLOBALS[' ']的区别
-
浅谈JS中String()与 .toString()的区别
-
浅谈php中mysql与mysqli的区别分析_PHP教程
-
java中extends与implements的区别浅谈
-
浅谈python中np.array的shape( ,)与( ,1)的区别
-
java中extends与implements的区别浅谈
-
浅谈php中mysql与mysqli的区别分析
-
浅谈HTTP中Get与Post的区别