博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
subprocess
阅读量:7137 次
发布时间:2019-06-28

本文共 4243 字,大约阅读时间需要 14 分钟。

Date: 2019-05-28

Author: Sun

运行一个进程

​ 运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。

subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。

1. subprocess.call()

函数格式如下:

call(*popenargs, timeout=None, **kwargs):    """Run command with arguments.  Wait for command to complete or    timeout, then return the returncode attribute.    The arguments are the same as for the Popen constructor.  Example:    retcode = call(["ls", "-l"])

父进程等待子进程完成

返回退出信息(returncode,相当于Linux exit code)

>>> import subprocess>>> retcode = subprocess.call(["ls", "-l"])#和shell中命令ls -a显示结果一样>>> print retcode0

或者是

>>> a = subprocess.call(['df','-hT'],shell=False)Filesystem    Type    Size  Used Avail Use% Mounted on/dev/sda2     ext4     94G   64G   26G  72% /tmpfs        tmpfs    2.8G     0  2.8G   0% /dev/shm/dev/sda1     ext4    976M   56M  853M   7% /boot

subprocess.check_call():用法与subprocess.call()类似,区别是,当返回值不为0时,直接抛出异常

>>> a = subprocess.check_call('df -hT',shell=True)Filesystem    Type    Size  Used Avail Use% Mounted on/dev/sda2     ext4     94G   64G   26G  72% /tmpfs        tmpfs    2.8G     0  2.8G   0% /dev/shm/dev/sda1     ext4    976M   56M  853M   7% /boot>>> print a0>>> a = subprocess.check_call('dfdsf',shell=True)/bin/sh: dfdsf: command not foundTraceback (most recent call last):  File "
", line 1, in
File "/usr/lib64/python2.6/subprocess.py", line 502, in check_call raise CalledProcessError(retcode, cmd)subprocess.CalledProcessError: Command 'dfdsf' returned non-zero exit status 127

2. subprocess.Popen()

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

函数形式如下:

class Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

Popen对象创建后,主程序不会自动等待子进程完成。我们必须调用对象的wait()方法,父进程才会等待 (也就是阻塞block)

import subprocessif __name__ == "__main__":    child = subprocess.Popen('ping -c  www.baidu.com', shell=True)    child.wait()    print('parent process')

​ 父进程在开启子进程之后并等待child的完成后,再运行print。

此外,你还可以在父进程中对子进程进行其它操作,比如我们上面例子中的child对象:代码如下:

child.poll() # 检查子进程状态

child.kill() # 终止子进程
child.send_signal() # 向子进程发送信号
child.terminate() # 终止子进程

子进程的标准输入、标准输出和标准错误, 如下属性分别表示:

child.stdin
child.stdout
child.stderr

示例,将一个子进程的输出,作为另一个子进程的输入:

import subprocesschild1 = subprocess.Popen(["cat","/etc/passwd"], stdout=subprocess.PIPE)child2 = subprocess.Popen(["grep","0:0"],stdin=child1.stdout, stdout=subprocess.PIPE)out = child2.communicate()

案例分析:

在工作中经常会遇到这样的需求:

需要采用python来运行一个shell脚本,如何优雅的操作呢?

解决方案:

​ 用python的subprocess去执行传递过来的脚本,通常情况下subprocess都能运行的很好,完成脚本的执行并返回。

可以采用如下代码实现:

# -*- coding: utf-8 -*-__author__ = 'sun'__date__ = '2019/5/28 18:26'import subprocessfrom threading import Timerimport osimport timeimport signalclass TestSubProcess(object):    def __init__(self):        self.stdout = []        self.stderr = []        self.timeout = 6        self.is_timeout = False    def timeout_callback(self, p):        print('exe time out call back')        try:            p.kill()            # os.killpg(p.pid, signal.SIGKILL)        except Exception as error:            print(error)    def run(self):        stdout = open('/tmp/subprocess_stdout', 'wb')        stderr = open('/tmp/subprocess_stderr', 'wb')        cmd = ['bash', '/home/xxx/while_test.sh']        ps = subprocess.Popen(cmd, stdout=stdout.fileno(), stderr=stderr.fileno())        my_timer = Timer(self.timeout, self.timeout_callback, [ps])        my_timer.start()        print(ps.pid)        try:            print("start to count timeout; timeout set to be %d \n" % (self.timeout,))            ps.wait()        finally:            my_timer.cancel()            stdout.flush()            stderr.flush()            stdout.close()            stderr.close()if __name__ == "__main__":    tsp = TestSubProcess()    tsp.run()

总结:

​ 关于p = subprocess.Popen,最好用p.communicate.而不是直接用p.wait(), 因为p.wait()有可能因为子进程往PIPE写的时候写满了,但是子进程还没有结束,导致子进程阻塞,而父进程一直在wait(),导致父进程阻塞。而且p.wait()和p.communicate不能一起用,因为p.communicate里面也会去调用wait()。

转载于:https://www.cnblogs.com/sunBinary/p/10940885.html

你可能感兴趣的文章
Android系统联系人全特效实现(上),分组导航和挤压动画
查看>>
ATS项目更新(4) 更新DLL到远程服务器
查看>>
Bzoj 1426 收集邮票
查看>>
mysql面试题
查看>>
mac 多显示器焦点快速切换
查看>>
第六周学习进度报告
查看>>
【ASP.NET开发】ASP.NET(MVC)三层架构知识的学习总结 分类: ...
查看>>
[译]ZOOKEEPER RECIPES-Leader Election
查看>>
微信小程序用户数据解密
查看>>
nginx发布静态网页
查看>>
Hadoop 面试题之一
查看>>
有关方法重载的实例(例4-10)
查看>>
用数组模拟邻接表
查看>>
ubuntu13.04 编译环境
查看>>
**Git中的AutoCRLF与SafeCRLF换行符问题
查看>>
heibernate增删改查总结一下自己的不足
查看>>
Git使用教程及常用命令大全
查看>>
数据持久化-- json、pickle
查看>>
更适用于JavaScript的设计模式:面向委托的设计,了解一下?(上)
查看>>
Android布局文件layout.xml的一些属性值
查看>>