subprocess模块可以生成新的进程,连接到它们的input/output/error管道,同时获取它们的返回码。
# ################### subprocess.run 使用
def subprocess_run():
result1 = subprocess.run(["adb", "devices"])
print("result1:", result1)
print("----------")
result2 = subprocess.run("adb devices", shell=True, check=True)
print("result2:", result2)
print("----------")
result3 = subprocess.run(["adb", "devices"], stdout=subprocess.PIPE)
print("result3:", result3)
print(type(result3))
subprocess_run()
""" 输出如下
List of devices attached
338b123f0504 device
result1: CompletedProcess(args=['adb', 'devices'], returncode=0)
----------
List of devices attached
338b123f0504 device
result2: CompletedProcess(args='adb devices', returncode=0)
----------
result3: CompletedProcess(args=['adb', 'devices'], returncode=0, stdout=b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n')
"""
# ################### subprocess.call使用
def subprocess_call():
result1 = subprocess.call(["adb", "devices"])
print("result1:", result1)
print("----------")
result2 = subprocess.call(["adb", "devices"], stdout=subprocess.PIPE)
print("result2:", result2)
subprocess_call()
"""结果
List of devices attached
338b123f0504 device
result1: 0
----------
result2: 0
"""
# ################### subprocess.check_call
def subprocess_check_call():
result1 = subprocess.check_call(["adb", "devices"])
print("result1:", result1)
print("----------")
result2 = subprocess.check_call(["adb", "devices"], stdout=subprocess.PIPE)
print("result2:", result2)
subprocess_check_call()
"""结果
List of devices attached
338b123f0504 device
result1: 0
----------
result2: 0
"""
# ################### subprocess.check_output
def subprocess_check_output():
result1 = subprocess.check_output(["adb", "devices"])
print("result1:", result1)
print("----------")
result2 = subprocess.run(["adb", "devices"], stdout=subprocess.PIPE).stdout
print("result2:", result2)
subprocess_check_output()
"""结果
result1: b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
----------
result2: b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
"""
执行cmd命令,返回值为命令执行的输出结果(字符串类型);执行失败,不会抛出异常(类似os.popen(cmd).read());
cmd:参数,字符串类型;
执行cmd命令,返回值为元组类型(命令执行状态, 命令执行的输出结果);元组中命令执行状态为0,表示执行成功;命令执行状态为1,表示执行失败;
cmd:参数,字符串类型;
# subprocess.getoutput或getstatusoutput使用
def subprocess_get_output():
result1 = subprocess.getoutput("adb devices")
print("result1:", result1)
print(type(result1))
print("**** subprocess.getstatusoutput ****")
result2 = subprocess.getstatusoutput("adb devices")
print("result2:", result2)
print(type(result2))
subprocess_get_output()
"""结果
**** subprocess.getoutput ****
result1: List of devices attached
338b123f0504 device
**** subprocess.getstatusoutput ****
result2: (0, 'List of devices attached \n338b123f0504\tdevice\n')
"""
subprocess.Popen类用于在一个新进程中执行一个子程序,上述subprocess函数均是基于subprocess.Popen类;
Popen类的构造函数,返回结果为subprocess.Popen对象;
下列 PopenObject 为 subprocess.Popen 对象
PopenObject.stdin:
若PopenObject中stdin为PIPE,则返回一个可写流对象;若encoding或errors参数被指定或universal_newlines参数为True,则此流是一个文件流,否则为字节流。
若PopenObject中stdin不是PIPE,则属性为None。
stdin输入流非None,可执行写操作即PopenObject.stdin.write(s)
PopenObject.stdout:
若PopenObject中stdout为PIPE,则返回一个可读流对象;若encoding或errors参数被指定或universal_newlines参数为True,则此流是一个文件流,否则为字节流。
若PopenObject中stdout不是PIPE,则属性为None。
stdout输出流非None,可执行读操作即PopenObject.stdout.read()或.readlines()
PopenObject.stderr:
若PopenObject中stderr为PIPE,则返回一个可读流对象;若encoding或errors参数被指定或universal_newlines参数为True,则此流是一个文件流,否则为字节流。
若PopenObject中stderr不是PIPE,则属性为None。
stderr错误流非None,可执行读操作即PopenObject.stderr.read()或.readlines()
def subprocess_Popen1():
print("***通过communicate函数分别输出PopenObject对象的输出流和错误流***")
args = [["adb", "devices"], ["adb", "devices11"]]
for arg in args:
popen_object = subprocess.Popen(arg, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
object_stdout, object_stderr = popen_object.communicate()
output = {"popen_object": popen_object,
"object_stdout": object_stdout,
"object_stderr": object_stderr}
print(output)
"""
{'popen_object': , 'object_stdout': b'List of devices attached \r\n106D111805005938\tdevice\r\n\r\n', 'object_stderr': b''}
{'popen_object': , 'object_stdout': b'', 'object_stderr': b'Android Debug Bridge version 1.0.31\r\n\r\n -a .....}
"""
print("***通过stdout和stderr方法输出PopenObject对象输出流和错误流***")
p0 = subprocess.Popen(["adb", "devices"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
object_stdout = p0.stdout.read()
p0.stdout.close()
object_stderr = p0.stderr.read()
p0.stderr.close()
print(object_stdout) # 结果:b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
print(object_stderr) # 结果:b''
print("***Popen对象stdin写入功能:使用stdout和stderr输出")
args = ["python", "python1"]
for arg in args:
p4 = subprocess.Popen([arg], shell=True, stdout=subprocess.PIPE,
stdin=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
p4.stdin.write("print('hello')")
p4.stdin.close()
out = p4.stdout.read()
p4.stdout.close()
err = p4.stderr.read()
p4.stderr.close()
print("out:%s err:%s" % (out, err))
"""
***Popen对象stdin写入功能
out:hello
err:
out: err:'python1' 不是内部或外部命令,也不是可运行的程序或批处理文件。
"""
print("***Popen对象stdin写入功能:使用communicate输出")
p4 = subprocess.Popen(["python"], stdout=subprocess.PIPE,
stdin=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
p4.stdin.write("print('hello')")
output = p4.communicate()
print(output) # 结果:('hello\n', '')
print("***不含encoding参数***")
p1 = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE)
out1 = p1.stdout.readlines()
print(out1) # 结果: [b'List of devices attached \r\n', b'106D111805005938\tdevice\r\n', b'\r\n']
print("***含encoding参数***")
p2 = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE, encoding="utf-8")
out2 = p2.stdout.readlines()
print(out2) # 结果: ['List of devices attached \n', '106D111805005938\tdevice\n', '\n']
print("***Popen对象检查命令是否结束,等待进程结束")
print(p2.poll()) # 结果: None
print(p2.wait()) # 结果: 0
print(p2.poll()) # 结果: 0
print("***Popen对象communicate函数,它会阻塞父进程直至子进程完成")
p3 = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE)
out = p3.communicate()[0]
print(out) # 结果:b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
print(p3.poll()) # 结果:0
subprocess_Popen1()
def subprocess_Popen2():
"""
1. 通过管道功能,实现adb shell ps | findstr top功能
2. 直接为args赋值为一个字符串,实现adb shell ps | findstr top功能
:return:
"""
print("***通过管道方式***")
p1 = subprocess.Popen(["adb", "shell", "ps"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["findstr", "top"], stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p2.communicate()
print(out, err) # 结果:b'shell 8508 8504 2600 1044 c004e5f8 b6f40938 S top\r\r\n' b''
print("***通过传一个字符串方式***")
p3 = subprocess.Popen("adb shell ps | findstr top", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p3.communicate()
print(out, err) # 结果:b'shell 8508 8504 2600 1044 c004e5f8 b6f40938 S top\r\r\n' b''
subprocess_Popen2()
报错信息
Traceback (most recent call last):
File "C:\Users\fenglepeng\.conda\envs\py37\lib\threading.py", line 926, in _bootstrap_inner
self.run()
File "C:\Users\fenglepeng\.conda\envs\py37\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\fenglepeng\.conda\envs\py37\lib\subprocess.py", line 1267, in _readerthread
buffer.append(fh.read())
UnicodeDecodeError: 'gbk' codec can't decode byte 0xac in position 421: illegal multibyte sequence
解决
# 参数中增加 encoding='utf-8'
sub = subprocess.Popen(command, shell=True, cwd=cwd, universal_newlines=True,stdout=subprocess.PIPE, stdin=subprocess.PIPE,stderr=subprocess.PIPE, encoding='utf-8')