Python中的subprocess模块

时间:2023-03-08 17:50:38
Python中的subprocess模块

Subprocess干嘛用的?

subprocess模块是python从2.4版本开始引入的模块。主要用来取代 一些旧的模块方法,如os.system、os.spawn*、os.popen*、commands.*等。subprocess通过子进程来执行外部指令,并通过input/output/error管道,获取子进程的执行的返回信息。

也就是说subprocess就是OS模块的升级版。

subprocess模块中的常用函数

函数 描述
subprocess.run() Python 3.5中新增的函数。执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。
subprocess.call() 执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd)。
subprocess.check_call() Python 2.5中新增的函数。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。其功能等价于subprocess.run(..., check=True)。
subprocess.check_output() Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。
subprocess.getoutput(cmd) 接收字符串格式的命令,执行命令并返回执行结果,其功能类似于os.popen(cmd).read()和commands.getoutput(cmd)。
subprocess.getstatusoutput(cmd) 执行cmd命令,返回一个元组(命令执行状态, 命令执行结果输出),其功能类似于commands.getstatusoutput()。

1.subprocess.call


父进程等待子进程执行命令,返回子进程执行命令的状态码,如果出现错误,不进行报错

第二个参数默认为False,Flase参数为的时候命令需要通过列表的方式传入,为True的时候可以直接传入命令。

【在Python的console界面中我们是能够看到命令结果的,只是获取不到。想获取执行的返回结果,请看check_output。】

【不进行报错解释:如果我们执行的命令在执行时,操作系统不识别,系统会返回一个错误,如:abc命令不存在,这个结果会在console界面中显示出来,但是我们的Python解释器不会提示任何信息,如果想让Python解释器也进行报错,请看check_call】

>>> import subprocess
>>> obj = subprocess.call(['df','-h'],shell=False)
文件系统 容量 已用 可用 已用% 挂载点
udev 5.8G 0 5.8G 0% /dev
tmpfs 1.2G 1.8M 1.2G 1% /run
/dev/sda6 393G 137G 237G 37% /
tmpfs 5.8G 51M 5.8G 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 5.8G 0 5.8G 0% /sys/fs/cgroup
tmpfs 1.2G 48K 1.2G 1% /run/user/1000
/dev/sda5 412G 26G 386G 7% /media/i3ekr/软件
/dev/sda1 121G 24G 97G 20% /media/i3ekr/F6AE5B1CAE5AD529
>>> obj = subprocess.call(('df -h'),shell=True)
文件系统 容量 已用 可用 已用% 挂载点
udev 5.8G 0 5.8G 0% /dev
tmpfs 1.2G 1.8M 1.2G 1% /run
/dev/sda6 393G 137G 237G 37% /
tmpfs 5.8G 49M 5.8G 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 5.8G 0 5.8G 0% /sys/fs/cgroup
tmpfs 1.2G 48K 1.2G 1% /run/user/1000
/dev/sda5 412G 26G 386G 7% /media/i3ekr/软件
/dev/sda1 121G 24G 97G 20% /media/i3ekr/F6AE5B1CAE5AD529
注:shell=True参数会让subprocess.Popen接受字符串类型的变量作为命令,并调用shell去执行这个字符串.见而言之就是将输入的参数调用shell去执行,如果不调用那可能就会出现命令找不到的情况.
当shell=False是,subprocess.Popen只接受数组变量作为命令,并将数组的第一个元素作为命令,剩下的全部作为该命令的参数。 默认情况下为false.

2.subprocess.check_call()


用法和call作用一样,和call的区别是返回值不为0(也就是命令不正确)的时候直接抛出异常。

>>> obj = subprocess.check_call('qwe',shell=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/subprocess.py", line 181, in check_call
retcode = call(*popenargs, **kwargs)
File "/usr/lib/python2.7/subprocess.py", line 168, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib/python2.7/subprocess.py", line 390, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1025, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
>>> obj = subprocess.check_call('df',shell=False)
文件系统 1K-块 已用 可用 已用% 挂载点
udev 6013400 0 6013400 0% /dev
tmpfs 1208056 1836 1206220 1% /run
/dev/sda6 411798952 143162248 247648800 37% /
tmpfs 6040264 48768 5991496 1% /dev/shm
tmpfs 5120 4 5116 1% /run/lock
tmpfs 6040264 0 6040264 0% /sys/fs/cgroup
tmpfs 1208052 48 1208004 1% /run/user/1000
/dev/sda5 431498236 27213864 404284372 7% /media/i3ekr/软件
/dev/sda1 125830140 24482072 101348068 20% /media/i3ekr/F6AE5B1CAE5AD529

可以用来判断用户命令是否出错可以搭配try来使用。

3.subprocess.Popen()


在一些复杂场景中,我们需要将一个进程的执行输出作为另一个进程的输入。在另一些场景中,我们需要先进入到某个输入环境,然后再执行一系列的指令等。这个时候我们就需要使用到suprocess的Popen()方法。该方法有以下参数:

args:shell命令,可以是字符串,或者序列类型,如list,tuple。

bufsize:缓冲区大小,可不用关心

stdin,stdout,stderr:分别表示程序的标准输入,标准输出及标准错误

shell:与上面方法中用法相同

cwd:用于设置子进程的当前目录

env:用于指定子进程的环境变量。如果env=None,则默认从父进程继承环境变量

universal_newlines:不同系统的的换行符不同,当该参数设定为true时,则表示使用\n作为换行符

4.获取命令执行后返回的结果:

>>> import subprocess
>>> com = subprocess.Popen('ifconfig',stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> data = com.stdout.read()
>>> data
'enp3s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n inet 10.41.8.24 netmask 255.255.252.0 broadcast 10.41.11.255\n inet6 fe80::a993:220a:2a:a488 prefixlen 64 scopeid 0x20<link>\n ether 98:40:bb:20:25:b0 txqueuelen 1000 (Ethernet)\n RX packets 7041415 bytes 6473395772 (6.0 GiB)\n RX errors 0 dropped 0 overruns 0 frame 0\n TX packets 6470453 bytes 3937057528 (3.6 GiB)\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\n\nlo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536\n inet 127.0.0.1 netmask 255.0.0.0\n inet6 ::1 prefixlen 128 scopeid 0x10<host>\n loop txqueuelen 1000 (Local Loopback)\n RX packets 775007 bytes 96639605 (92.1 MiB)\n RX errors 0 dropped 0 overruns 0 frame 0\n TX packets 775007 bytes 96639605 (92.1 MiB)\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\n\nvmnet1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n inet 172.16.189.1 netmask 255.255.255.0 broadcast 172.16.189.255\n inet6 fe80::250:56ff:fec0:1 prefixlen 64 scopeid 0x20<link>\n ether 00:50:56:c0:00:01 txqueuelen 1000 (Ethernet)\n RX packets 0 bytes 0 (0.0 B)\n RX errors 0 dropped 0 overruns 0 frame 0\n TX packets 1930 bytes 0 (0.0 B)\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\n\nvmnet8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n inet 172.16.150.1 netmask 255.255.255.0 broadcast 172.16.150.255\n inet6 fe80::250:56ff:fec0:8 prefixlen 64 scopeid 0x20<link>\n ether 00:50:56:c0:00:08 txqueuelen 1000 (Ethernet)\n RX packets 0 bytes 0 (0.0 B)\n RX errors 0 dropped 0 overruns 0 frame 0\n TX packets 1923 bytes 0 (0.0 B)\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\n\nwlp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n inet 10.42.0.1 netmask 255.255.255.0 broadcast 10.42.0.255\n inet6 fe80::3e8b:4ca8:230f:4f1e prefixlen 64 scopeid 0x20<link>\n ether 70:1c:e7:25:e8:47 txqueuelen 1000 (Ethernet)\n RX packets 394488 bytes 27416908 (26.1 MiB)\n RX errors 0 dropped 3 overruns 0 frame 0\n TX packets 805283 bytes 1207252086 (1.1 GiB)\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\n\n'