day5-subprocess模块
概述
在运维的工作中,经常需要和操作系统的命令做交互,我们如何用python去跟操作系统之间做交互呢?下面就来说说我们今天需要学习的模块:subprocess。
产生背景
我们在没有subprocess这个模块的时候,怎么去和操作系统做交互的呢?下面我们先说说这三个模块:os.system()、os.popen()、commands。
1.os.system()
用法:调用操作系统命令,只返回命令的执行状态(0:成功,非0:失败),不返回命令的执行结果。
>>> import os >>> os.system("ls -l") total 0 drwx------@ 46 huwei staff 1564 7 26 23:54 Desktop drwx------@ 4 huwei staff 136 6 28 01:22 Documents drwx------+ 53 huwei staff 1802 7 19 22:33 Downloads drwx------@ 59 huwei staff 2006 6 29 21:17 Library drwx------+ 3 huwei staff 102 6 17 19:46 Movies drwx------+ 3 huwei staff 102 6 17 19:46 Music drwx------+ 4 huwei staff 136 6 17 19:49 Pictures drwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public drwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects drwxr-xr-x 5 huwei staff 170 7 13 00:19 test 0 #返回命令执行状态 >>> res = os.system("ls -l") total 0 drwx------@ 46 huwei staff 1564 7 26 23:54 Desktop drwx------@ 4 huwei staff 136 6 28 01:22 Documents drwx------+ 53 huwei staff 1802 7 19 22:33 Downloads drwx------@ 59 huwei staff 2006 6 29 21:17 Library drwx------+ 3 huwei staff 102 6 17 19:46 Movies drwx------+ 3 huwei staff 102 6 17 19:46 Music drwx------+ 4 huwei staff 136 6 17 19:49 Pictures drwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public drwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects drwxr-xr-x 5 huwei staff 170 7 13 00:19 test >>> res 0 #0表示:执行成功 >>> res = os.system("lsdcwdf") sh: lsdcwdf: command not found >>> res 32512 #非0表示:执行失败
2.os.popen()
用法:调用操作系统命令,只返回命令执行结果,不返回命令执行状态
>>> import os >>> os.popen("ls -l") <os._wrap_close object at 0x101116908> #默认返回内存地址 >>> res = os.popen("ls -l") >>> a = res.read() #打印返回结果 >>> print(a) total 0 drwx------@ 46 huwei staff 1564 7 26 23:54 Desktop drwx------@ 4 huwei staff 136 6 28 01:22 Documents drwx------+ 53 huwei staff 1802 7 19 22:33 Downloads drwx------@ 59 huwei staff 2006 6 29 21:17 Library drwx------+ 3 huwei staff 102 6 17 19:46 Movies drwx------+ 3 huwei staff 102 6 17 19:46 Music drwx------+ 4 huwei staff 136 6 17 19:49 Pictures drwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public drwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects drwxr-xr-x 5 huwei staff 170 7 13 00:19 test
解析:执行popen()不是直接返回命令的执行结果,而是需要read一下,这是因为popen相当于打开了一个文件,它把结果存到文件中,只不过它是相当于存在内存中了,但是你好像打开文件的样子去取一样。
3.commands模块
用法:如果想既想保存命令执行结果,又想保存命令执行状态,那么在Python 2.7中有个commands模块,且该模块只支持Linux系统,不过在Python 3.5之后就没有这个用法了。
>>> import commands 导入模块 >>> commands.getstatusoutput("ls -l") #以元组的形式返回 (0, 'total 0\ndrwx------@ 46 huwei staff 1564 7 26 23:54 Desktop\ndrwx------@ 4 huwei staff 136 6 28 01:22 Documents\ndrwx------+ 53 huwei staff 1802 7 19 22:33 Downloads\ndrwx------@ 59 huwei staff 2006 6 29 21:17 Library\ndrwx------+ 3 huwei staff 102 6 17 19:46 Movies\ndrwx------+ 3 huwei staff 102 6 17 19:46 Music\ndrwx------+ 4 huwei staff 136 6 17 19:49 Pictures\ndrwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public\ndrwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects\ndrwxr-xr-x 5 huwei staff 170 7 13 00:19 test') >>> res = commands.getstatusoutput("ls -l") >>> res[0] 0 #返回的命令执行状态 >>> res[1] #返回的命令执行结果 'total 0\ndrwx------@ 46 huwei staff 1564 7 26 23:54 Desktop\ndrwx------@ 4 huwei staff 136 6 28 01:22 Documents\ndrwx------+ 53 huwei staff 1802 7 19 22:33 Downloads\ndrwx------@ 59 huwei staff 2006 6 29 21:17 Library\ndrwx------+ 3 huwei staff 102 6 17 19:46 Movies\ndrwx------+ 3 huwei staff 102 6 17 19:46 Music\ndrwx------+ 4 huwei staff 136 6 17 19:49 Pictures\ndrwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public\ndrwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects\ndrwxr-xr-x 5 huwei staff 170 7 13 00:19 test' >>> print(res[1]) total 0 drwx------@ 46 huwei staff 1564 7 26 23:54 Desktop drwx------@ 4 huwei staff 136 6 28 01:22 Documents drwx------+ 53 huwei staff 1802 7 19 22:33 Downloads drwx------@ 59 huwei staff 2006 6 29 21:17 Library drwx------+ 3 huwei staff 102 6 17 19:46 Movies drwx------+ 3 huwei staff 102 6 17 19:46 Music drwx------+ 4 huwei staff 136 6 17 19:49 Pictures drwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public drwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects drwxr-xr-x 5 huwei staff 170 7 13 00:19 test
subprocess模块
这个模块打算替换以下模块的功能:
os.system #调用系统命令
os.spawn* #产生一个新进程取执行命令
所以在Python 3.5之后,subprocess模块能够帮助我们实现既想保存命令执行结果,又想保存命令的执行状态,下面我们就来看看该模块的具体用法:
1.subprocess.run()
用法:返回命令执行结果,且该命令只支持Python 3.5b版本之后
>>> import subprocess >>> subprocess.run(["df","-h"]) #解析传入参数的列表 Filesystem Size Used Avail Capacity iused ifree %iused Mounted on /dev/disk1 233Gi 39Gi 193Gi 17% 792426 4294174853 0% / devfs 183Ki 183Ki 0Bi 100% 632 0 100% /dev map -hosts 0Bi 0Bi 0Bi 100% 0 0 100% /net map auto_home 0Bi 0Bi 0Bi 100% 0 0 100% /home /Users/huwei/Downloads/Fantastical 2.app 233Gi 37Gi 196Gi 16% 790977 4294176302 0% /private/var/folders/1y/z_lsdnxn73g0rvpxj99kf11h0000gn/T/AppTranslocation/E3115EFA-6D8A-4F19-8873-800D9F60F9AD CompletedProcess(args=['df', '-h'], returncode=0) #需要交给Linux shell自己解析,则传入命令字符串,shell=True >>> subprocess.run("df -h |grep huwei",shell=True) /Users/huwei/Downloads/Fantastical 2.app 233Gi 37Gi 196Gi 16% 790977 4294176302 0% /private/var/folders/1y/z_lsdnxn73g0rvpxj99kf11h0000gn/T/AppTranslocation/E3115EFA-6D8A-4F19-8873-800D9F60F9AD CompletedProcess(args='df -h |grep huwei', returncode=0)
解析:
1.执行的命令需要让python去解释执行这个命令,执行的命令以及参数,需要以列表的形式传入。
2.但是如果需要交给Linux shell环境去解析的,这传入命令的字符串,并且声明shell=True即可。
2.subprocess.call()
用法:执行命令,返回命令执行状态,0 或者 非0
>>>import subprocess >>> subprocess.call(["ls","-l"]) total 0 drwx------@ 46 huwei staff 1564 7 26 23:54 Desktop drwx------@ 4 huwei staff 136 6 28 01:22 Documents drwx------+ 53 huwei staff 1802 7 19 22:33 Downloads drwx------@ 59 huwei staff 2006 6 29 21:17 Library drwx------+ 3 huwei staff 102 6 17 19:46 Movies drwx------+ 3 huwei staff 102 6 17 19:46 Music drwx------+ 4 huwei staff 136 6 17 19:49 Pictures drwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public drwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects drwxr-xr-x 5 huwei staff 170 7 13 00:19 test 0 >>> a = subprocess.call(["ls","-l"]) total 0 drwx------@ 46 huwei staff 1564 7 26 23:54 Desktop drwx------@ 4 huwei staff 136 6 28 01:22 Documents drwx------+ 53 huwei staff 1802 7 19 22:33 Downloads drwx------@ 59 huwei staff 2006 6 29 21:17 Library drwx------+ 3 huwei staff 102 6 17 19:46 Movies drwx------+ 3 huwei staff 102 6 17 19:46 Music drwx------+ 4 huwei staff 136 6 17 19:49 Pictures drwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public drwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects drwxr-xr-x 5 huwei staff 170 7 13 00:19 test >>> a 0 #返回命令的执行状态
3.subprocess.check_call()
用法:执行命令,如果命令结果为0,就正常返回,否则抛出异常
>>> subprocess.check_call(["ls","-l"]) total 0 drwx------@ 46 huwei staff 1564 7 26 23:54 Desktop drwx------@ 4 huwei staff 136 6 28 01:22 Documents drwx------+ 53 huwei staff 1802 7 19 22:33 Downloads drwx------@ 59 huwei staff 2006 6 29 21:17 Library drwx------+ 3 huwei staff 102 6 17 19:46 Movies drwx------+ 3 huwei staff 102 6 17 19:46 Music drwx------+ 4 huwei staff 136 6 17 19:49 Pictures drwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public drwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects drwxr-xr-x 5 huwei staff 170 7 13 00:19 test 0 >>>a = subprocess.check_call(["ls","-l"]) 0 >>> subprocess.check_call(["ls2","-l"]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/subprocess.py", line 576, in check_call retcode = call(*popenargs, **kwargs) File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/subprocess.py", line 557, in call with Popen(*popenargs, **kwargs) as p: File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/subprocess.py", line 947, in __init__ restore_signals, start_new_session) File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/subprocess.py", line 1551, in _execute_child raise child_exception_type(errno_num, err_msg) FileNotFoundError: [Errno 2] No such file or directory: 'ls2'
4.subprocess.getstatusoutput()
用法:接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果
>>>import subprocess >>> subprocess.getstatusoutput("ls -l") (0, 'total 0\ndrwx------@ 46 huwei staff 1564 7 26 23:54 ) # 执行状态 , 执行结果
5.subprocess.getoutput()
用法:接收字符串格式命令,并返回结果
>>> subprocess.getoutput("ls -l") 'total 0\ndrwx------@ 46 huwei staff 1564 7 26 23:54 #返回执行结果
6.subprocess.check_output()
用法:执行命令,并返回结果,注意是返回结果,不是打印,下例结果返回给res
>>> res = subprocess.check_output(["ls","-l"]) >>> res b'total 0\ndrwx------@ 46 huwei staff 1564 7 26 23:54 #是以bytes类型返回的
subprocess.Popen()
上面那些方法,底层都是封装的subprocess.Popen,下面我们来看看Popen方法:
1.stdout
用法:标准输出
>>> res = subprocess.Popen("ls -l",shell=True,stdout=subprocess.PIPE) #需要管道标准输出 >>> res.stdout.read() #标准输出 b'total 0\ndrwx------@ 46 huwei staff 1564 7 26 23:54 Desktop\ndrwx------@ 4 huwei staff 136 6 28 01:22 Documents\ndrwx------+ 53 huwei staff 1802 7 19 22:33 Downloads\ndrwx------@ 59 huwei staff 2006 6 29 21:17 Library\ndrwx------+ 3 huwei staff 102 6 17 19:46 Movies\ndrwx------+ 3 huwei staff 102 6 17 19:46 Music\ndrwx------+ 4 huwei staff 136 6 17 19:49 Pictures\ndrwxr-xr-x+ 5 huwei staff 170 6 17 19:46 Public\ndrwxr-xr-x 4 huwei staff 136 6 21 13:59 PycharmProjects\ndrwxr-xr-x 5 huwei staff 170 7 13 00:19 test\n' >>> obj.stdout.close() Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'obj' is not defined >>> res.stdout.close() #关闭标准输出 >>> res.stdout.read() Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: read of closed file
2.stdin
用法:标准输入
>>> obj = subprocess.Popen([b"python3.5"],stdout=subprocess.PIPE,stdin=subprocess. >>> obj.stdin.write(b"print('dick')") #标准输入 13 >>> obj.stdin.close() #关闭标准输入 怎么样才能将输入的数据读出来呢? >>> out_put = obj.stdout.read() #标准输出 >>> out_put #输出的数据 b'dick\n' >>> obj.stdout.close() #关闭标准输出 >>> out_put_err = obj.stderr.read() #输出错误 >>> out_put_err #为空 b'' >>> obj.stderr.close() #关闭输出错误
3.stderr
用法:标准错误
>>> res = subprocess.Popen("lsffdew -l",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) >>> res.stderr.read() #标准输出错误 b'/bin/sh: lsffdew: command not found\n' >>> res.stderr.close() #关闭启动程序的标准错误 >>> res.stderr.read() Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: read of closed file
注意:上面的命令格式为什么都需要加PIPE,其实它是将执行命令的结果数据存入管道(PIPE),再通过read()读出来。
4.poll()
用法:定时检查命令有没有执行完毕,执行完毕返回0,没有完毕返回None
>>> import subprocess >>> res = subprocess.Popen("sleep 20;echo 'hello'",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) >>> res.stdout.read() #命令执行过程。。。。。 b'hello\n' >>> #在命令执行过程中,我们可以使用以下命令判断 >>> print(res.poll()) None # None表示未执行完毕 >>> print(res.poll()) 0 #0 表示执行完毕
5.wait()
用法:等待命令执行完成,并返回结果状态
>>> import subprocess >>> res = subprocess.Popen("sleep 20;echo 'hello'",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) >>> res.wait() #命令执行过程。。。。。 0
6.terminate()
用法:杀掉所启动的进程
>>> import subprocess >>> res = subprocess.Popen("sleep 20;echo 'hello'",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) >>> res.terminate() #杀掉启动的进程 >>> res.stdout.read() #杀掉后,标准输出为空 b''
7.communicate()
用法: 执行的过程传数据
>>> res = subprocess.Popen([b"python"],stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE) >>> res.stdin.write(b"print 'dick'") #标准输入 12 >>> out_error_list = res.communicate(timeout=10) >>> print(out_error_list) #输入的结果 (b'dick\n', b'')
8.pid
用法:获取当前执行子shell程序的进程号
>>> import subprocess >>> res = subprocess.Popen("sleep 20;echo 'hello'",shell=True,stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE) >>> res.pid #获取Unix shell环境的进程号 6734
可用参数:
- args:shell命令,可用是字符串或者序列类型(如:list,元组)
- bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他缓冲区大小,负值 系统缓冲
- stdin,stdout,stderr:分别表示程序的标准输入,输出,错误句柄
- preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
- close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入,输出,错误管道,所以不能将close_fds设置为True同时重定向子进程的标准输入,输出与错误(stdin,stdout,stderr)
- shell:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入,输出,错误管道,所以不能将close_fds设置为True同时重定向子进程的标准输入,输出与错误(stdin,stdout,stderr)
- cwd:用于设置子进程的当前目录
- env:用于指定子进程的环境变量。如果env =None,子进程的环境变量将从父进程中继承
- universal_newlines:不同系统的换行符不同,True -> 同意使用 \n
- startupinfo与createionflags只在windows下有效将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如,主窗口外观,进程的优先级等等
终端输入的命令分为2种:
- 输入即可得到输出,如:ifconfig
- 输入进行某环境,依赖再输入,如:python
需要交互的实例:communicate()示例
subprocess实现sudo 自动输入密码
>>>import subprocess >>>subprocess.Popen("echo ‘abc123‘ | sudo -S apt-get install vim",shell=True)