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. oracle的 分表 详解 -----表分区

    此文从以下几个方面来整理关于分区表的概念及操作:         1.表空间及分区表的概念         2.表分区的具体作用         3.表分区的优缺点         4.表分区的几种类 ...

  2. 计算java对象的内存占用

    代码引用自:https://blog.csdn.net/antony9118/article/details/54317637  感谢博主分享: import java.util.ArrayList; ...

  3. spring 及 spring boot 资源文件配置

    Spring配置文件引入xml文件: <import resource=" " />标签使用总结 https://www.cnblogs.com/javahr/p/83 ...

  4. POJ3768 Katu Puzzle

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  5. SPOJ8222 NSUBSTR - Substrings

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  6. java classloader原理深究

    前面已经写过一篇关于java classloader的拙文java classloader原理初探. 时隔几年,再看一遍,觉得有些地方显得太过苍白,于是再来一篇: 完成一个Java类之后,经过java ...

  7. HTop 防止进程重复显示

    按F2 选择 Display options 选择 Hide userland threads 比Top更加好用!

  8. Spring Boot技术栈博客笔记(1)

    要实现的核心功能 用户管理 安全设置 博客管理 评论管理 点赞管理 分类管理 标签管理 首页搜索 核心技术 数据存储 随着spring3发布以来,spring团队减少使用xml配置的使用,采用大量约定 ...

  9. vue-cli Uncaught SyntaxError: Use of const in strict mode解决办法

    vue-cli初始化项目,开发环境运行项目使用了webpack-dev-server,而最新版本webpack-dev-server@2.9.1运行项目时,并不能成功的把es6语法转化为es5,所以在 ...

  10. HDU 5687 字典树入门

    Problem C Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total ...