Python Linux系统管理之Python中执行外部命令
一、简介
有很多需求需要在Python中执行shell命令、启动子进程,并捕获命令的输出和退出状态码,类似于Java中的Runtime类库。本文将介绍subprocess模块的定位,然后介绍subprocess模块提供的便利函数,最后介绍Popen这个类的使用方法。
二、subprocess模块的使用
1、call
call函数的定义如下:
subprocess.call(args,*,stdin=None,stout=None,stderr=None,shell=False)
call函数将允许由args参数制定的命令直到命令结束。call函数的返回值是命令的退出状态码,工程师可以通过退出状态码判断命令是否执行成功。如下所示:
In [1]: import subprocess In [2]: subprocess.call([‘ls’,’-l’]) total 8 -rw-r–r–. 1 root root 0 Sep 24 10:52 1.txt
-rw-r–r–. 1 root root 0 Sep 24 10:52 2.txt -rw-r–r–. 1 root root 3736 Sep 24 10:51 demo.tar.gz -rw-r–r–. 1 root root 929 Sep 24 10:52 demo.zip Out[2]: 0 In [3]: subprocess.call(“exit 1”,shell = True) Out[3]: 1 |
注:如果设置shell=True,Python会先运行一个shell,再用shell解释字符串,而不是传递一个列表。
2、check_call
check_all与call类似,只是遇到异常情况返回的形式不同。如果命令执行成功,下面会返回0;如果命令执行失败,它会抛出subprocess.CalledProcessError异常,相关案例如下所示:
In [5]: subprocess.check_call([“ls”,”-l”]) total 8 -rw-r–r–. 1 root root 0 Sep 24 10:52 1.txt -rw-r–r–. 1 root root 0 Sep 24 10:52 2.txt
-rw-r–r–. 1 root root 3736 Sep 24 10:51 demo.tar.gz -rw-r–r–. 1 root root 929 Sep 24 10:52 demo.zip Out[5]: 0 In [6]: subprocess.check_call(“exit 1”,shell = True) ————————————————————————— CalledProcessError Traceback (most recent call last) <ipython-input-6-f13e6678cc55> in <module>() —-> 1 subprocess.check_call(“exit 1”,shell = True) /usr/local/lib/python3.7/subprocess.py in check_call(*popenargs, **kwargs) 326 if cmd is None: 327 cmd = popenargs[0] –> 328 raise CalledProcessError(retcode, cmd) 329 return 0 330 CalledProcessError: Command ‘exit 1’ returned non-zero exit status 1. |
3、check_output
从上面的输出结果可以看到,call和check_call函数直接将命令的输出结果输出到命令行终端,这种返回结果的形式很有可能是你不想要的。在实际工作过程中,一般会对获取命令的结果进行进一步处理,或者将命令的输出打印到日志文件中。如下所示:
In [1]: import subprocess In [2]: output = subprocess.check_output([‘df’,’-h’]) In [3]: print(output) b’Filesystem Size Used Avail Use{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} Mounted on\n/dev/mapper/centos-root 50G 1.7G 49G 4{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /\ndevtmpfs 1.9G 0 1.9G 0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /dev\ntmpfs 1.9G 0 1.9G 0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /dev/shm\ntmpfs 1.9G 12M 1.9G 1{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /run\ntmpfs 1.9G 0 1.9G 0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /sys/fs/cgroup\n/dev/mapper/centos-home 106G 246M 105G 1{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /home\n/dev/sda1 1014M 184M 831M 19{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /boot\ntmpfs 378M 0 378M 0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /run/user/0\n’
In [4]: lines = output.split(b’\n’) In [5]: lines Out[5]: [b’Filesystem Size Used Avail Use{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} Mounted on’, b’/dev/mapper/centos-root 50G 1.7G 49G 4{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /’, b’devtmpfs 1.9G 0 1.9G 0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /dev’, b’tmpfs 1.9G 0 1.9G 0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /dev/shm’, b’tmpfs 1.9G 12M 1.9G 1{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /run’, b’tmpfs 1.9G 0 1.9G 0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /sys/fs/cgroup’, b’/dev/mapper/centos-home 106G 246M 105G 1{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /home’, b’/dev/sda1 1014M 184M 831M 19{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /boot’, b’tmpfs 378M 0 378M 0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b} /run/user/0′, b”] In [6]: for line in lines[1:-1]: …: if line: …: print(line.split()[-2]) …: b’4{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b}’ b’0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b}’ b’0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b}’ b’1{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b}’ b’0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b}’ b’1{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b}’ b’19{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b}’ b’0{815ac408a99669c280d890a3c1592527154068adde55fb55fc5b84dc9fd9f61b}’ |
如果想要捕捉退出状态码,可以通过抛出的subprocess.CalledProcessError异常。
import subprocess try: output = subprocess.check_output(‘cmd’,’arg1′ ,’arg2′) except subprocess.CalledProcessError as e:
output = e.output code = e.returncode |
默认情况下,check_output命令只会捕捉命令的标准输出。如果想捕捉命令的错误输出,需要将错误输出重定向到标准输出。如下所示:
output = subprocess.check_output([‘cmd’,’arg1′ ,’arg2′],stderr= subprocess.STDOUT) |