博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用subprocess模块调用系统命令
阅读量:7066 次
发布时间:2019-06-28

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

一、os.system(commandString)

import osstatusCode=os.system("powershell sleep 3 ;echo 天下大势为我所控")print("over",statusCode)
  • 这里使用了powershell来执行sleep命令,在cmd里面是没有sleep命令的。
  • 会发现os.system(commandString)是阻塞的。
  • 这个函数类似C语言里面的stdlib.h中的system命令
  • 这种方法只负责运行程序并获取程序结束状态值,无法获取输出,输出会直接打印到stdout,所以要想获取输出也可以重定向一下stdout,然而没有这个必要,因为可以用下面的subprocess方法。

这种方法只在确保命令不会出错并且需要阻塞的情况下使用。

二、os.popen(commandString)

这种方法已经不鼓励使用了,可以跳过。

import ospipe=os.popen("powershell sleep 3 ;echo 天下大势为我所控")s=pipe.read()print(s)

这种方法直接接受运行的输出结果,缺点是无法获取程序的结束状态。os.system()只获取状态不获取输出,os.popen()只获取输出不获取状态。这两者都是历史糟粕,不必再看。subprocess功能丰富灵活,是更好的选择。

三、使用commands模块

这个模块在Python3中已经废弃了

import commands(status, output) = commands.getstatusoutput('cat /proc/cpuinfo')print status,output

四、鼓励使用:subprocess

4.1简介

前面介绍的几种方法都存在各种问题,以后用subprocess就对了。它用于替换以下函数(包括上面介绍的函数):

os.systemos.spawn*os.popen*popen2.*commands.*

spawn这个单词意思是“鱼、蛙等大量产卵”,在计算机领域中表示一个线程创建另一个线程。

4.2 subprocess模块的三个方法

  • subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)->statusCode
    利用stdin、stdout、stderr可以重定向,shell=True可以使用更丰富的命令,此方法阻塞直到程序返回,返回结果为退出码。
  • subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False)->statusCode
    此方法和call非常像,唯一的区别是,当程序退出码不为0时,抛出CalledProcessError异常,而不是让用户手动判断状态码。
  • subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)->outputString
    此方法和check_call非常像,唯一的区别是它的返回值是进程的stdout中的内容,因此参数中没有stdout参数。

这三个方法共同点是它们都是阻塞的。

官网上有一个警告,说指定它们的stdout和stderr容易造成死锁。

Note Do not use stdout=PIPE or stderr=PIPE with this function as that can deadlock based on the child process output volume. Use Popen with the communicate() method when you need pipes.

举例:

import subprocessstatusCode=subprocess.call("echo one",shell=True)#相当于system命令,只返回状态值,并打印输出到stdoutprint(statusCode)statusCode=subprocess.check_call(["echo","  two"],shell=True)print(statusCode)output=subprocess.check_output("echo three",shell=True)#只获取outputprint(output)

4.3 常用参数说明

  • args参数
    args参数可以是两种类型中的任意一种:字符串和字符串数组。使用字符串数组是更好的选择,因为参数中可能包含空白字符(例如cat "ha ha.txt"),字符串数组比直接传入字符串要安全一些。注意:当args为一个字符串时,需要满足两个条件:(1)args必须是可执行程序的名字(无法为它指定任何参数);(2)shell=True。这两个条件有一个满足,args就可以传入字符串。
  • stdin,stdout,stderr
    可取值为PIPE、文件描述符(int类型)、file类型的对象、None。
  • universal_newlines
    此值为True表示stdout和stderr的换行符一律采用\n

4.4 CalledProcessError

在上述三个主要函数中,check_call()和check_output()可能会抛出CalledProcessError错误。CalledProcessError错误包括以下三个属性:

  • returncode:Exit status of the child process.
  • cmd:Command that was used to spawn the child process.
  • output:Output of the child process if this exception is raised by check_output(). Otherwise, None.

4.5 Popen类

如果觉得以上三个方法不够灵活,就使用Popen类。创建Popen类之后,子进程就开始运行了,并不会阻塞当前进程。

上述三个方法都是对Popen类的封装,Popen类的构造函数的参数跟上述三个函数有重合的部分,此外,还包括一下参数:

  • preexec_fn
    预先执行的函数,在执行命令之前可以执行preexec_fn进行一些初始化
  • close_fds
    if close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. (Unix only). Or, on Windows, if close_fds is true then no handles will be inherited by the child process. Note that on Windows, you cannot set close_fds to true and also redirect the standard handles by setting stdin, stdout or stderr.
  • cwd
    程序运行的当前目录
  • env
    若env为None,默认集成父进程的环境变量;否则env应该是一个字典。

Popen对象包含丰富的函数和属性:

  • poll():检查子进程是否执行完毕,不阻塞
  • wait(timeout):等待子进程一段时间,如果子进程在时限内运行结束,正常向下执行。否则抛出超时异常。
  • communicate(input)->(stdoutContent,stderrContent):和子进程进行交互,主进程向子进程stdin写入input这样的字符串,函数返回子进程当前的输出内容和错误内容(直到读到底为止)。此函数对子进程的stdin、stdout、stderr有特殊要求。
  • send_signal(),terminate(),kill():向子进程发送SIGTERM、SIGKILL之类的信号。
  • stdin,stdout,stderr:Popen对象的三个属性
  • pid:Popen对象的进程ID
  • returnCode:Popen对象的状态码

例1:

import subprocessobj = subprocess.Popen("mkdir t3", shell=True, cwd='/home/dev',)     #在cwd目录下执行命令

例2:

import subprocessobj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)obj.stdin.write("print(1)\n")obj.stdin.write("print(2)")obj.stdin.close()cmd_out = obj.stdout.read()obj.stdout.close()cmd_error = obj.stderr.read()obj.stderr.close()print(cmd_out)print(cmd_error)

例3:

import subprocessobj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)obj.stdin.write("print(1)\n")obj.stdin.write("print(2)")out_error_list = obj.communicate()print(out_error_list)import subprocessobj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)out_error_list = obj.communicate('print("hello")')print(out_error_list)

4.6 使用Popen可能会遇到的问题

(1)windows平台下虽然命令不带.cmd、.exe也能够运行,但是在使用Popen时必须指定全名,否则会找不到可执行文件。

(2)当shell参数为True时,process.kill()和process.terminate()函数仅仅杀死了shell进程,而shell进程的子进程却还活着,这样就产生了许多僵尸进程,正确的解决方法是:杀死一个组进程。

pro = subprocess.Popen(s, shell=True,preexec_fn=os.setsid)#使用setsid函数初始化进程,setsid函数的用途是创建新的进程组,否则最后关闭一组进程时把自己也杀掉了try:    pro.wait(1)  # 最多等待1秒钟except Exception as ex:    print("over time ", pro.pid)    os.killpg(os.getpgid(pro.pid), signal.SIGTERM)  # 杀死一个进程组    raise ex

参考资料

官网教程

转载地址:http://dcxll.baihongyu.com/

你可能感兴趣的文章
thinkphp的taglib的使用方法
查看>>
tecplot批量导出图片_Fluent 后处理软件Tecplot宏批量处理cas,dat为图片
查看>>
锂电池放空后充不进电_充电锂电池,只几个月不用,为什么就再也充不进电了?...
查看>>
golang mutex 初始化_Golang连接池的几种实现案例
查看>>
docker可以把应用及其相关的_等离子表面处理机相关应用及其特点
查看>>
发电厂电气部分第三版pdf_喜讯、大唐锡林浩特发电厂660mw机组投产运行
查看>>
mysql 数据库操作通用类_mysql 数据库操作通用类
查看>>
mysql多数据库多实例配置_MySQL多实例配置方案
查看>>
python创建线段_在绘图图中添加线段的简洁方法(使用python/jupyter笔记本)?
查看>>
wkhtmltoimage 卡住了_用rails做一个简单的长微博生成工具
查看>>
什么叫组网_组网是什么意思
查看>>
如何使用mysql数据库做网站_php小型数据库(不用mysql做网站)
查看>>
mysql date to javascript_Convert MySql DateTime stamp into JavaScript's Date format
查看>>
mysql临时表仅对当前用户_mysql临时表问题
查看>>
mysql报错文档_mysql报错小记-Can't create test file xxx lower-test
查看>>
mysql数据库基础简介_MySQL数据库命令的基础简介
查看>>
java arraylist方法_Java的ArrayList方法及示例
查看>>
java语言新特性_Java语言的新特性
查看>>
java try finally_Java中try、finally语句中有return时的执行情况 [转]
查看>>
java io nio nio2_Java 对象序列化 NIO NIO2详细介绍及解析
查看>>