`
这些年
  • 浏览: 399854 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

调用系统程序(转)

 
阅读更多

subprocess的目标是启动一个新的进程并与之进行通讯。

subprocess.Popen

这个模块主要就提供一个类Popen:

class subprocess.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)

这堆东西真让人抓狂:

args

字符串或者列表

bufsize

0 无缓冲
1 行缓冲
其他正值 缓冲区大小
负值 采用默认系统缓冲(一般是全缓冲)

executable

一般不用吧,args字符串或列表第一项表示程序名

stdin
stdout
stderr

None 没有任何重定向,继承父进程
PIPE 创建管道
文件对象
文件描述符(整数)
stderr 还可以设置为 STDOUT

preexec_fn

钩子函数, 在fork和exec之间执行。(unix)

close_fds

unix 下执行新进程前是否关闭0/1/2之外的文件
windows下不继承还是继承父进程的文件描述符

shell

为真的话
unix下相当于args前面添加了 "/bin/sh“ ”-c”
window下,相当于添加"cmd.exe /c"

cwd

设置工作目录

env

设置环境变量

universal_newlines

各种换行符统一处理成 '\n'

startupinfo

window下传递给CreateProcess的结构体

creationflags

windows下,传递CREATE_NEW_CONSOLE创建自己的控制台窗口

  • 当初最感到困扰的就是 args 参数。可以是一个字符串,可以是一个列表。

 

subprocess.Popen(["gedit","abc.txt"])
subprocess.Popen("gedit abc.txt")

这两个之中,后者将不会工作。因为如果是一个字符串的话,必须是程序的路径才可以。(考虑unix的api函数 exec,接受的是字符串列表)

  • 但是下面的可以工作

 

subprocess.Popen("gedit abc.txt", shell=True)

这是因为它相当于

subprocess.Popen(["/bin/sh", "-c", "gedit abc.txt"])

都成了sh的参数,就无所谓了

  • 在Windows下,下面的却又是可以工作的

 

subprocess.Popen(["notepad.exe", "abc.txt"])
subprocess.Popen("notepad.exe abc.txt")

这是由于windows下的api函数CreateProcess接受的是一个字符串。即使是列表形式的参数,也需要先合并成字符串再传递给api函数。

  • 类似上面

 

subprocess.Popen("notepad.exe abc.txt" shell=True)

等价于

subprocess.Popen("cmd.exe /C "+"notepad.exe abc.txt" shell=True)

subprocess.call*

模块还提供了几个便利函数(这本身也算是很好的Popen的使用例子了)

  • call() 执行程序,并等待它完成

 

def call(*popenargs, **kwargs):
    return Popen(*popenargs, **kwargs).wait()
  • check_call() 调用前面的call,如果返回值非零,则抛出异常

 

def check_call(*popenargs, **kwargs):
    retcode = call(*popenargs, **kwargs)
    if retcode:
        cmd = kwargs.get("args")
        raise CalledProcessError(retcode, cmd)
    return 0
  • check_output() 执行程序,并返回其标准输出

 

def check_output(*popenargs, **kwargs):
    process = Popen(*popenargs, stdout=PIPE, **kwargs)
    output, unused_err = process.communicate()
    retcode = process.poll()
    if retcode:
        cmd = kwargs.get("args")
        raise CalledProcessError(retcode, cmd, output=output)
    return output

Popen对象

该对象提供有不少方法函数可用。而且前面已经用到了wait()/poll()/communicate()

poll()

检查是否结束,设置返回值

wait()

等待结束,设置返回值

communicate()

参数是标准输入,返回标准输出和标准出错

send_signal()

发送信号 (主要在unix下有用)

terminate()

终止进程,unix对应的SIGTERM信号,windows下调用api函数TerminateProcess()

kill()

杀死进程(unix对应SIGKILL信号),windows下同上

stdin
stdout
stderr

参数中指定PIPE时,有用

pid

进程id

returncode

进程返回值

 

 

 

1. subprocess以及常用的封装函数

当我们运行python的时候,我们都是在创建并运行一个进程。正如我们在Linux进程基础中介绍的那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序(fork,exec见Linux进程基础)。

 

subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

 

使用subprocess包中的函数创建子进程的时候,要注意:

1) 在创建子进程之后,父进程是否暂停,并等待子进程运行。

2) 函数返回什么

3) 当returncode不为0时,父进程如何处理。

 

subprocess.call()
父进程等待子进程完成
返回退出信息(returncode,相当于exit code,见Linux进程基础)

 

subprocess.check_call()

父进程等待子进程完成

返回0

检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性,可用try...except...来检查(见Python错误处理)。

 

subprocess.check_output()

父进程等待子进程完成

返回子进程向标准输出的输出结果

检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性和output属性,output属性为标准输出的输出结果,可用try...except...来检查。

 

这三个函数的使用方法相类似,我们以subprocess.call()来说明:

import subprocess
rc = subprocess.call(["ls","-l"])
我们将程序名(ls)和所带的参数(-l)一起放在一个表中传递给subprocess.call()

 

可以通过一个shell来解释一整个字符串:

import subprocess
out = subprocess.call("ls -l", shell=True)
out = subprocess.call("cd ..", shell=True)
我们使用了shell=True这个参数。这个时候,我们使用一整个字符串,而不是一个表来运行子进程。Python将先运行一个shell,再用这个shell来解释这整个字符串。

shell命令中有一些是shell的内建命令,这些命令必须通过shell运行,$cd。shell=True允许我们运行这样一些命令。

 

2. Popen

实际上,我们上面的三个函数都是基于Popen()的封装(wrapper)。这些封装的目的在于让我们容易使用子进程。当我们想要更个性化我们的需求的时候,就要转向Popen类,该类生成的对象用来代表子进程。

 

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

import subprocess
child = subprocess.Popen(["ping","-c","5","www.google.com"])
print("parent process")
从运行结果中看到,父进程在开启子进程之后并没有等待child的完成,而是直接运行print。

 

对比等待的情况:

import subprocess
child = subprocess.Popen(["ping","-c","5","www.google.com"])
child.wait()
print("parent process")


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

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

child.kill()           # 终止子进程

child.send_signal()    # 向子进程发送信号

child.terminate()      # 终止子进程

 

子进程的PID存储在child.pid

 

3. 子进程的文本流控制

(沿用child子进程) 子进程的标准输入,标准输出和标准错误也可以通过如下属性表示:

child.stdin

child.stdout

child.stderr

 

我们可以在Popen()建立子进程的时候改变标准输入、标准输出和标准错误,并可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe):

import subprocess
child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
out = child2.communicate()
print(out)
subprocess.PIPE实际上为文本流提供一个缓存区。child1的stdout将文本输出到缓存区,随后child2的stdin从该PIPE中将文本读取走。child2的输出文本也被存放在PIPE中,直到communicate()方法从PIPE中读取出PIPE中的文本。

要注意的是,communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成。

 

我们还可以利用communicate()方法来使用PIPE给子进程输入:

import subprocess
child = subprocess.Popen(["cat"], stdin=subprocess.PIPE)
child.communicate("vamei")
我们启动子进程之后,cat会等待输入,直到我们用communicate()输入"vamei"。

分享到:
评论

相关推荐

    Android调用系统程序

    在Android系统中,调用系统程序是常见的操作,可以实现应用程序间的交互,增强用户体验。本文将深入探讨如何在Android应用中调用系统程序,包括设置页面、Wi-Fi设置页面、发送电子邮件以及联系人页面的调用。 首先...

    js调用系统程序

    本文将深入探讨如何使用JavaScript调用系统程序,特别是在JavaScript中调用系统软键盘这一特定应用场景。 首先,JavaScript本身是受限于浏览器的安全沙箱模型,它无法直接执行操作系统级别的命令。然而,通过一些...

    Windows程序调用系统

    使用本软件可以不受网吧管理系统的限制调用windows自身的各种系统程序以及系统设置等,也可以用本软件快速的打开一些windows的高级系统和设置程序,使用运行窗口可以让电脑高手更灵活的调用windows程序,本软件拥有...

    abaqus调用子程序的方法

    "Abaqus调用子程序的方法" ABAQUS 是一种功能强大的有限元分析软件,但是在使用过程中,用户经常会遇到调用子程序的问题。调用子程序是ABAQUS的一个重要功能,它允许用户编写自己的 Fortran 子程序来实现特定的计算...

    易语言API动态调用子程序源码

    API(Application Programming Interface)是操作系统提供给程序员调用的接口,允许程序与操作系统进行交互,执行特定任务。在易语言中,API动态调用子程序是一项重要的功能,它使得开发者可以灵活地使用Windows API...

    S7-200SMART 中调用子程序时需要注意的问题汇总.docx

    在S7-200SMART PLC编程中,子程序的调用是实现复杂逻辑控制的重要手段。然而,不恰当的子程序调用可能导致意想不到的...在编程过程中,始终查阅系统手册,了解各种指令和功能的工作原理,是解决问题和优化程序的关键。

    北大Nachos系统调用实习报告

    Nachos 操作系统中,系统调用包括文件系统调用和执行用户程序相关的系统调用两部分。 文件系统调用 文件系统调用是 Nachos 操作系统中的一种系统调用,用于访问文件系统。文件系统调用包括 Create、Open、Close、...

    wince下应用程序如何调用驱动程序

    在 Windows CE 操作系统中,应用程序可以通过 DeviceIoControl 函数调用驱动程序,实现对硬件的控制。在驱动程序中,需要实现 xxx_iocontrol 函数,该函数主要是对 IO 口的控制,可以根据不同的 IO 操作码实现不同的...

    易语言调用系统自带的“运行命令”

    在易语言中,调用系统自带的“运行命令”是一项基础且实用的功能,可以用来执行操作系统中的各种命令,比如打开程序、文件、网页等。下面将详细介绍如何在易语言中实现这一功能,并探讨相关的编程知识。 首先,我们...

    谷歌内核-调用本地程序 亲测可用

    在IT领域,尤其是在软件开发和系统集成中,有时我们需要让应用程序之间进行交互,例如从一个程序启动另一个程序。本示例以"谷歌内核-调用本地程序 亲测可用"为主题,说明了如何在使用谷歌浏览器(Chrome)内核的环境...

    C#调用exe程序并运行

    在C#编程中,有时我们需要调用已存在的可执行文件(exe)来执行特定的任务,这通常是通过系统进程或者操作系统的API来实现的。本文将详细介绍如何在C#中调用exe程序并运行,以及一些相关的注意事项。 首先,C#提供...

    易语言调用系统邮件程序

    本主题聚焦于易语言如何调用系统邮件程序,实现邮件发送功能。在易语言中,通过特定的函数和方法,我们可以与操作系统进行交互,调用内置的邮件客户端或者第三方邮件服务来发送邮件。 首先,调用系统邮件程序的核心...

    易语言汇编动态调用子程序源码

    在易语言中,通过汇编动态调用子程序,开发者可以实现对系统更底层的操作,提高程序性能,或者完成一些易语言自身难以实现的功能。 动态调用子程序是程序设计中的一个重要概念,通常在运行时根据需要加载和执行特定...

    添加新的系统调用

    为了验证新系统调用的功能,可以编写用户空间的测试程序,利用`syscall()`或`__NR_newsyscall`(系统调用号)来调用新接口。 6. **安全性和性能考虑**:添加系统调用需谨慎,因为它会直接影响系统的稳定性和性能。...

    cpp-一个微小的系统调用跟踪程序和调试器实现

    在IT领域,系统调用跟踪程序(如strace)和调试器(如gdb)是开发者的重要工具,用于理解和调试程序的行为。这个名为"cpp-一个微小的系统调用跟踪程序和调试器实现"的项目,显然是一个使用C++语言实现的简易版strace...

    汇编语言子程序及系统调用

    在汇编语言中,子程序和系统调用是两个重要的概念,它们允许程序员组织代码并利用操作系统提供的服务。 **子程序设计**是指将一段重复使用的代码封装成独立的程序单元,以便在需要时通过调用来执行。子程序可以提高...

    易语言使用汇编调用子程序

    DLL是Windows操作系统中的一种共享库,可以被多个程序同时调用。 3. **在易语言中调用**:在易语言程序中,使用“外部调用”指令引用DLL中的函数。需要指定函数名、参数类型、返回值类型,以及DLL文件的路径。 4. ...

    web调用本地程序示例

    在IT领域,Web调用本地程序是一种常见的技术需求,它允许网页通过某种方式与用户的本地计算机进行交互,执行特定的任务。这种技术广泛应用于自动化工作流程、远程服务支持、软件更新等场景。本示例提供了实现这一...

    linux中添加系统调用

    系统调用是一种特殊的子程序,由操作系统内核提供,用户程序通过特定的接口(通常在C语言中是`syscall()`函数)调用。当执行系统调用时,处理器会切换到内核模式,执行相应的内核代码,然后返回到用户模式,确保了...

    ICT程序调用系统

    "ICT程序调用系统"是信息技术(ICT)领域的一个关键组件,主要应用于测试行业中。这个系统设计的目的是为了高效、安全地在服务器端执行测试程序。在传统的测试流程中,选择正确的程序进行调用可能会出现人为错误,这...

Global site tag (gtag.js) - Google Analytics