Python笔记之subprocess——子进程模块

subprocess最早在2.4版本引入,用来代替多个旧模块和函数:

os.system
os.open
os.spawn
os.popen

popen2.
commands.

API说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 运行由args指定的命令,结束后返回return code
subprocess.call(["ping", "www.baidu.com"])
subprocess.call("exit 1", shell=True) # 使用Shell解释整个字符串,或运行Shell内的命令

# 返回输出值。若返回码为非零,则抛出 CalledProcessError异常
subprocess.check_output("hexo -v", shell=True)

# 更灵活
p = subprocess.Popen(["ping","www.baidu.com"], stdout=subprocess.PIPE)
# 也可以 p = subprocess.Popen("ping www.baidu.com", stdout=subprocess.PIPE, shell=True)
p.wait() # 阻塞父进程,直到子进程完成
p.stdout.read().decode('gbk') # 读取输出结果,注意Windows 终端输出是GBK编码。需要Popen指定了stdout

# 利用subprocess.PIPE将多个子进程的输入和输出连接在一起
p1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["wc"], stdin=p1.stdout,stdout=subprocess.PIPE)
out = p2.communicate() # 阻塞父进程,直到子进程完成,此方法可以带参数,传给子进程

# 使用communicate()方法向子进程传输二进制数据
p = subprocess.Popen(['adb shell'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'adb help\nexit\n')
print(output.decode('utf-8'))
print('Exit code:', p.returncode)

# 其他方法
p.terminate() # 停止子程序
p.kill() # 杀死子进程

应用实例

一些简单例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 调用系统中cmd命令,显示命令执行的结果:
x=subprocess.check_output(["echo", "Hello World!"], shell=True) # echo是shell命令,必须指定参数为True

# 在python中显示文件内容:
y=subprocess.check_output(["type", "app2.cpp"], shell=True)

# 查看ipconfig -all命令的输出,并将将输出保存到文件tmp.log中:
handle = open(r'd:\tmp.log','wb')
subprocess.Popen(['ipconfig','-all'], stdout=handle)

# 查看网络设置ipconfig -all,保存到变量中
p = subprocess.Popen(['ipconfig','-all'], stdout=subprocess.PIPE,shell=True)
output, err = p.communicate()

# 频繁和子线程通信,不能使用communicate()
# 因为communicate通信一次之后即关闭了管道
p = subprocess.Popen(["wc"], stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=True)
p.stdin.write('your command')
p.stdin.flush()

连续输入和输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# test.py
import sys
while True:
line = sys.stdin.readline()
if not line:break
sys.stdout.write(line)
sys.stdout.flush()

# run.py
import sys
from subprocess import *
proc = Popen('./test.py',stdin=PIPE,stdout=PIPE,shell=True)
for line in sys.stdin: # 这一步脚本会接收键盘输入
proc.stdin.write(line)
proc.stdin.flush()
output = proc.stdout.readline()
sys.stdout.write(output)

实时获取子进程输出

1
2
3
4
5
6
7
8
9
10
11
12
import subprocess

def main():
p = subprocess.Popen("python -u sub.py", stdout = subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
line = p.stdout.readline()
if not line:
break
print(line)

if __name__ == '__main__':
main()

或者

1
2
3
4
5
6
7
8
9
import subprocess
import time

p = subprocess.Popen('ping 127.0.0.1 -n 10', stdout=subprocess.PIPE)
while p.poll() == None: # 检查子进程是否已经结束
print(p.stdout.readline())
time.sleep(1)
print(p.stdout.read())
print('returen code:', p.returncode)

参考资料

loveNight wechat
我的微信公众号,放一些有趣的内容,不定期更新。