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)
posted @ 2017-07-30 21:32  Mr.hu  阅读(137)  评论(0编辑  收藏  举报