python重要模块之subprocess模块

我们经常要通过python去执行系统的命令或者脚本,系统的shell命令是独立于你的python进程之外的,每执行一条命令,就相当于发起了一个新的进程,通过python调用系统命令或脚本的模块。

之前我们也学到过和系统交互的模块-os模块

In [1]: import os

In [2]: os.system('uname -a')
Linux host-10-200-137-195 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Out[2]: 0 # 命令的执行返回结果,0为执行成功,非0表示失败

除了so.system可以调用系统命令,commands和popen2等也可以,因为比较乱,所以官方推出了subprocess,目的就是提供统一的模块来实现对系统命令或脚本的调用。简单演示下commands的用法:

commands模块讲解

# commands模块,在python2中运行

>>> import commands  # 导入这个模块
>>> status,output = commands.getstatusoutput('ls')
>>> status # 代表shell命令的返回状态
0
>>> output # 代表shell命令你的执行结果
'anaconda-ks.cfg'

三种命令的执行方式

  • subprocess.run() # 官方推荐
  • subprocess.call() # 跟run()方法差不多,另一种写法
  • subprocess.Popen() # 上面各种方法的封装

run()方法

标准写法

subprocess.run(['df','-h'],stderr=subprocess.PIPE,stdout=subprocess.PIPE,check=True)

慢慢来讲:

In [2]: subprocess.run(['df','-h'])  # 这个是将shell命令拆分成列表的形式写
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 50G 2.2G 48G 5% /
devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 3.9G 8.4M 3.9G 1% /run
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/vda1 509M 175M 335M 35% /boot
tmpfs 783M 0 783M 0% /run/user/0
Out[2]: CompletedProcess(args=['df', '-h'], returncode=0) # 返回了一个对象 # 赋值
a = subprocess.run(['df','-h']) # 此时a就是返回的那个对象,通过这个对象,我们可以使用很多方法 In [3]: a # 就是返回的那个对象
Out[3]: CompletedProcess(args=['df', '-h'], returncode=0) In [4]: a.returncode # 查看shell命令执行状态
Out[4]: 0 In [5]: a.args # 查看所带的参数
Out[5]: ['df', '-h'] In [6]: a.check_returncode # 判断命令执行状态是否为0,不为0则报错
Out[6]: <bound method CompletedProcess.check_returncode of CompletedProcess(args=['df', '-h'], returncode=0)> In [7]: a.stdout In [8]: a.stderr

那么问题来了,为什么a.stdout和a.stderr没有输出任何东西呢?让我们来看看subprocess模块内部的工作机制吧?

通过python去执行Liunx命令,相当于发起了一个新的进程,我们比如: 在Word文档中把QQ打开了,word要占用内存,QQ也要占用内存,那么在word中能不能给QQ里的好友发送消息呢?

答案是不能的,因为:如果wold可以去访问QQ的内存数据,那么就可以通过QQ发送数据了,那么就会有一个问题出现,QQ被搞崩了,所以操作系统为了避免这样的事情发生,就严格的限制了每个进程在内存中都是独立的,我们再打个比方:在浏览器中复制粘贴,其实就是通过操作系统去实现的,操作系统也有着自己的内存,从浏览器中赋值的内容,然后通过操作系统导给QQ等,操作系统可以访问每个进程的内存。

python和shell的关系就是这样,subprocess帮我们发起了一个进程然后得到结果,python和shell之间是不互通的,如果想要互通,那么就需要有个桥梁,即python和操作系统之间的桥梁。

所以就会有这么一种写法了

subprocess.run([ls'','-l'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
其中PIPE就相当于是桥梁,stdout和stderr被称为标准输出
# 此时让我们再看一下运行结果
In [9]: a = subprocess.run(['ls','-l'],stdout=subprocess.PIPE,stderr=subprocess.PIPE) In [10]: a.stdout # 标准输出
Out[10]: b'total 4\n-rw-------. 1 root root 1224 Oct 15 2016 anaconda-ks.cfg\n' In [11]: a.stderr # 标准错误输出
Out[11]: b''

继续往下讲,在run()方法中,check=True是啥意思呢?写代码看下:

In [13]: a = subprocess.run(['ls','-ldada'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)  # 故意设置shell命令是错误的,结果并不检查
...: In [14]: a = subprocess.run(['ls','-lkjh'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True) # 检查shell命令是否正确,不正确则报错
---------------------------------------------------------------------------
CalledProcessError Traceback (most recent call last)
<ipython-input-14-0e63d8200326> in <module>()
----> 1 a = subprocess.run(['ls','-lkjh'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True) /usr/local/lib/python3.6/subprocess.py in run(input, timeout, check, *popenargs, **kwargs)
416 if check and retcode:
417 raise CalledProcessError(retcode, process.args,
--> 418 output=stdout, stderr=stderr)
419 return CompletedProcess(process.args, retcode, stdout, stderr)
420 CalledProcessError: Command '['ls', '-lkjh']' returned non-zero exit status 2. In [15]: a = subprocess.run(['ls','-lkjh'],stdout=subprocess.PIPE,stderr=subprocess.PIPE) In [16]: a = subprocess.run(['ls','-lkjh'],stdout=subprocess.PIPE,stderr=subprocess.PIPE),check=True
File "<ipython-input-16-15adea8e8d2f>", line 1
a = subprocess.run(['ls','-lkjh'],stdout=subprocess.PIPE,stderr=subprocess.PIPE),check=True
^
SyntaxError: can't assign to function call

如果想执行复杂的shell命令,让我们来看看怎么写?

In [17]: a = subprocess.run(['df','-h','|','grep','Used'],stdout=subprocess.PIPE,stderr=subprocess.PI
...: PE) # 刚刚的ls -l不就是这样的嘛一直拼参数怎么会报错了呢 In [18]: a.stderr # 我知道是错误的,故意直接写的是标准错误输出
Out[18]: b'df: \xe2\x80\x98|\xe2\x80\x99: No such file or directory\ndf: \xe2\x80\x98grep\xe2\x80\x99: No such file or directory\ndf: \xe2\x80\x98Used\xe2\x80\x99: No such file or directory\n' # 其实应该这样写
In [21]: a = subprocess.run('df -h | grep Used',stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True) In [22]: a.stdout
Out[22]: b'Filesystem Size Used Avail Use% Mounted on\n' In [23]: a.stderr
Out[23]: b''
# shell=True这样写就是告诉subprocess,你之前帮我拼参数,但是现在不用了,只需要把整条命令传递个shell去处理就行了

call()方法

废话不多说,直接看代码

In [24]: subprocess.call(['ls','-l'])
total 4
-rw-------. 1 root root 1224 Oct 15 2016 anaconda-ks.cfg
Out[24]: 0 # 命令执行的返回状态,0代表成功 # 执行命令,如果命令结果为0,就正常返回,否则抛异常
In [25]: subprocess.check_call(['ls','-l'])
total 4
-rw-------. 1 root root 1224 Oct 15 2016 anaconda-ks.cfg
Out[25]: 0 In [26]: subprocess.check_call(['ls','-lhgj'])
ls: invalid option -- 'j'
Try 'ls --help' for more information.
---------------------------------------------------------------------------
CalledProcessError Traceback (most recent call last)
<ipython-input-26-c38033ac38dc> in <module>()
----> 1 subprocess.check_call(['ls','-lhgj']) /usr/local/lib/python3.6/subprocess.py in check_call(*popenargs, **kwargs)
289 if cmd is None:
290 cmd = popenargs[0]
--> 291 raise CalledProcessError(retcode, cmd)
292 return 0
293 CalledProcessError: Command '['ls', '-lhgj']' returned non-zero exit status 2. # 接受字符串格式的命令,返回元组形式,第1个元素是执行状态,第2个是命令结果
In [27]: subprocess.getstatusoutput('ls /bin/ls')
Out[27]: (0, '/bin/ls') # 接收字符串格式命令,并返回结果
In [29]: subprocess.getoutput('df -h | grep Used')
Out[29]: 'Filesystem Size Used Avail Use% Mounted on' # 执行命令并返回结果,注意是返回结果,不是打印,

Popen()方法

常用参数

  • args:shell命令,可以是字符或者序列化类型(list,tuple)
  • stdint,stdout,stderr:分别表示程序的标准输入、输出、错误
  • preexec_fn:只在Unix平台下有效,用于指定一个可执行对象,它将在子进程运行之前被调用
  • shell:同上
  • cwd:用于指定子进程的当前目录
  • env:用于指定子进程的环境变量,如果env=None,子进程的环境变量将会从父进程中继承

下面这两条语句执行会有什么区别?

In [7]: a = subprocess.call('sleep 10',shell=True,stdout=subprocess.PIPE)  # 它会一直等待着这段代码执行完才结束

In [8]: a = subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)  # 相当于是有两个进程,主程序继续下一步行动,其余则另开一个新的进程执行sleep 10

如果你调用的命令或脚本需要哦执行10分钟,你的主程序不需卡在哪里等待10分钟,可以继续往下走干别的事情,每过一会,就可以通过poll()方法去检测一下这个命令是否执行完成。

Popen调用后会返回一个对象,可以通过这个对象拿到命令的执行结果或状态等,该对象有以下方法:

1.poll():查看这个进程的执行状态,没有执行完则不输出,执行正确输出0,错误非0

In [13]: a = subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)

In [14]: a.poll()

2.wait():等待这个进程结束,知道返回运行结果

In [15]: a = subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)

In [16]: a.wait()
Out[16]: 0

3.terminate():终止所启动的进程

4.kill():杀死所启动的进程

In [24]: a = subprocess.Popen('for i in $(seq 1 100);do sleep 1;echo $i >> sleep1.log;done',shell=True,stdou
...: t=subprocess.PIPE) In [25]: a.terminate # 这个是内存地址
Out[25]: <bound method Popen.terminate of <subprocess.Popen object at 0x7f49d85717f0>> In [26]: a.terminate() # 杀死进程的一种方法 In [28]: a = subprocess.Popen('for i in $(seq 1 100);do sleep 1;echo $i >> sleep1.log;done',shell=True,stdou
...: t=subprocess.PIPE) In [29]: a.kill() # 杀死进程的另一种方法

5.pid():获取子进程的pid

In [30]: a = subprocess.Popen('for i in $(seq 1 100);do sleep 1;echo $i >> sleep1.log;done',shell=True,stdou
...: t=subprocess.PIPE) In [33]: a.pid
Out[33]: 4931

现在讲一下Popen方法的其中几个参数

# cwd设置子进程的当前目录
In [4]: a = subprocess.Popen('echo $PWD;sleep 2',shell=True,cwd='/tmp',stdout=subprocess.PIPE) In [5]: a.stdout.read()
Out[5]: b'/tmp\n' # preexec_fn= 在子进程运行之前被调用 # 最后一个,与程序的交互,communicate(),发送数据到stdin,并从stdout接收输入,然后等待任务结束 这是一个猜数字的游戏1.py
11 import random
12
13 num = random.randint(1,100)
14 your_guess = int(input('your_guess:'))
15
16 if your_guess > num:
17 print('bigger')
18 elif yur_guess < num:
19 print('smaller')
20 else:
21 print('ok') 程序交互:
>>> import subprocess
>>> a = subprocess.Popen('python3 1.py',shell=True,stdout=subprocess.PIPE)
然后:
a.communicate(b'22') # 就可以了,我的xshell一运行就断开连接,所以,我就不演示啦。

python重要模块之subprocess模块的更多相关文章

  1. configparser模块,subprocess 模块,xlrd,xlwt ,xml 模块,面向对象

    1. configparser模块 2.subprocess 模块 3.xlrd,xlwt 4.xml 模块 5.面向对象 面向对象是什么? 是一种编程思想,指导你如何更好的编写代码 关注点在对象 具 ...

  2. [xml模块、hashlib模块、subprocess模块、os与sys模块、configparser模块]

    [xml模块.hashlib模块.subprocess模块.os与sys模块.configparser模块] xml模块 XML:全称 可扩展标记语言,为了能够在不同的平台间继续数据的交换,使交换的数 ...

  3. python学习道路(day7note)(subprocess模块,面向对象)

    1.subprocess模块   因为方法较多我就写在code里面了,后面有注释 #!/usr/bin/env python #_*_coding:utf-8_*_ #linux 上调用python脚 ...

  4. python笔记-9(subprocess模块、面向对象、socket入门)

    一.subprocess 模块 1.了解os.system()与os.popen的区别及不足 1.1 os.system()可以执行系统指令,将结果直接输出到屏幕,同时可以将指令是否执行成功的状态赋值 ...

  5. Python开发基础-Day15正则表达式爬虫应用,configparser模块和subprocess模块

    正则表达式爬虫应用(校花网) import requests import re import json #定义函数返回网页的字符串信息 def getPage_str(url): page_stri ...

  6. python基础之正则表达式爬虫应用,configparser模块和subprocess模块

    正则表达式爬虫应用(校花网) 1 import requests 2 import re 3 import json 4 #定义函数返回网页的字符串信息 5 def getPage_str(url): ...

  7. python - 标准库:subprocess模块

    subprocess的目的就是启动一个新的进程并且与之通信. subprocess模块中只定义了一个类: Popen. subprocess.Popen(args, bufsize=0, execut ...

  8. python-re模块和subprocess模块

    一.re模块 re中文为正则表达式,是字符串处理的常用工具,通常用来检索和替换符合某个模式的文本. 注:要搜索的模式和字符串都可以是unicode字符串(str)和8位字符串(bytes),但是不能将 ...

  9. os模块、os.path模块、shutil模块、configparser模块、subprocess模块

    一.os模块 os指的是操作系统 该模块主要用于处理与操作系统相关的操作,常用的是文件操作(读.写.删.复制.重命名). os.getcwd()  获取当前文件所在的文件夹路径 os.chdir()  ...

随机推荐

  1. openwrt的编译系统是如何制作根文件系统的

    答:分析以下makefile即可获取整个过程 以nxp layerscape系统的编译过程为例 1.分析target/linux/layerscape/image/Makefile的最后一句,这是一个 ...

  2. SpringMVC HttpMessageConverter 匹配规则

    以下内容,如有问题,烦请指出,谢谢! SpringMVC启动时会自动配置一些HttpMessageConverter,接收到http请求时,从这些Converters中选择一个符合条件的来进行Http ...

  3. [BZOJ3669]魔法森林

    Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...

  4. java 反序列化 漏洞

        java在反序列化的时候会默认调用被重写的readObject(ObjectInputStream )方法. 在远程服务端一个需要反序列化的接口中,比如一个web服务,他那个接口调用链中有反序 ...

  5. Anaconda 环境中使用pip安装时候出现的一些问题

    author:pprp date:18/8/12 --- 1. AttributeError: Module Pip has no attribute 'main' solution:降低pip的版本 ...

  6. [笔记整理]SQL Server 索引碎片 和 重建索引

    铺垫知识点: 数据库存储本身是无序的,建立了聚集索引,会按照聚集索引物理顺序存入硬盘.既键值的逻辑顺序决定了表中相应行的物理顺序 多数情况下,数据库读取频率远高于写入频率,索引的存在 为了读取速度牺牲 ...

  7. GridControl 史上最全的资料(一)

    GridControl详解(一)原汁原味的表格展示 Dev控件中的表格控件GridControl控件非常强大.不过,一些细枝末节的地方有时候用起来不好找挺讨厌的.使用过程中,多半借助Demo和英文帮助 ...

  8. 数据可视化——matplotlib(2)

    导入相关模块 import matplotlib.pyplot as plt import numpy as np import pandas as pd 图表设置 添加X.Y轴标签以及图标标题 a ...

  9. 最简js深浅拷贝说明

    1.浅拷贝 浅拷贝是拷贝引用,拷贝后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响.  浅拷贝分两种情况: 1.直接拷贝源对象的引用 2. 源对象拷贝实例,但其属性对象(类型为Object, ...

  10. centos 6.6 配置xdmcp远程桌面

    1.首先安装 xdm软件:yum install xdm vi /etc/X11/xdm/Xaccess: * allow  vi /etc/gdm/custom.conf: [security] A ...