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 无缓冲 |
executable |
一般不用吧,args字符串或列表第一项表示程序名 |
stdin |
None 没有任何重定向,继承父进程 |
preexec_fn |
钩子函数, 在fork和exec之间执行。(unix) |
close_fds |
unix 下执行新进程前是否关闭0/1/2之外的文件 |
shell |
为真的话 |
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 |
参数中指定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应用中调用系统程序,包括设置页面、Wi-Fi设置页面、发送电子邮件以及联系人页面的调用。 首先...
本文将深入探讨如何使用JavaScript调用系统程序,特别是在JavaScript中调用系统软键盘这一特定应用场景。 首先,JavaScript本身是受限于浏览器的安全沙箱模型,它无法直接执行操作系统级别的命令。然而,通过一些...
使用本软件可以不受网吧管理系统的限制调用windows自身的各种系统程序以及系统设置等,也可以用本软件快速的打开一些windows的高级系统和设置程序,使用运行窗口可以让电脑高手更灵活的调用windows程序,本软件拥有...
"Abaqus调用子程序的方法" ABAQUS 是一种功能强大的有限元分析软件,但是在使用过程中,用户经常会遇到调用子程序的问题。调用子程序是ABAQUS的一个重要功能,它允许用户编写自己的 Fortran 子程序来实现特定的计算...
API(Application Programming Interface)是操作系统提供给程序员调用的接口,允许程序与操作系统进行交互,执行特定任务。在易语言中,API动态调用子程序是一项重要的功能,它使得开发者可以灵活地使用Windows API...
在S7-200SMART PLC编程中,子程序的调用是实现复杂逻辑控制的重要手段。然而,不恰当的子程序调用可能导致意想不到的...在编程过程中,始终查阅系统手册,了解各种指令和功能的工作原理,是解决问题和优化程序的关键。
Nachos 操作系统中,系统调用包括文件系统调用和执行用户程序相关的系统调用两部分。 文件系统调用 文件系统调用是 Nachos 操作系统中的一种系统调用,用于访问文件系统。文件系统调用包括 Create、Open、Close、...
在 Windows CE 操作系统中,应用程序可以通过 DeviceIoControl 函数调用驱动程序,实现对硬件的控制。在驱动程序中,需要实现 xxx_iocontrol 函数,该函数主要是对 IO 口的控制,可以根据不同的 IO 操作码实现不同的...
在易语言中,调用系统自带的“运行命令”是一项基础且实用的功能,可以用来执行操作系统中的各种命令,比如打开程序、文件、网页等。下面将详细介绍如何在易语言中实现这一功能,并探讨相关的编程知识。 首先,我们...
在IT领域,尤其是在软件开发和系统集成中,有时我们需要让应用程序之间进行交互,例如从一个程序启动另一个程序。本示例以"谷歌内核-调用本地程序 亲测可用"为主题,说明了如何在使用谷歌浏览器(Chrome)内核的环境...
在C#编程中,有时我们需要调用已存在的可执行文件(exe)来执行特定的任务,这通常是通过系统进程或者操作系统的API来实现的。本文将详细介绍如何在C#中调用exe程序并运行,以及一些相关的注意事项。 首先,C#提供...
本主题聚焦于易语言如何调用系统邮件程序,实现邮件发送功能。在易语言中,通过特定的函数和方法,我们可以与操作系统进行交互,调用内置的邮件客户端或者第三方邮件服务来发送邮件。 首先,调用系统邮件程序的核心...
在易语言中,通过汇编动态调用子程序,开发者可以实现对系统更底层的操作,提高程序性能,或者完成一些易语言自身难以实现的功能。 动态调用子程序是程序设计中的一个重要概念,通常在运行时根据需要加载和执行特定...
为了验证新系统调用的功能,可以编写用户空间的测试程序,利用`syscall()`或`__NR_newsyscall`(系统调用号)来调用新接口。 6. **安全性和性能考虑**:添加系统调用需谨慎,因为它会直接影响系统的稳定性和性能。...
在IT领域,系统调用跟踪程序(如strace)和调试器(如gdb)是开发者的重要工具,用于理解和调试程序的行为。这个名为"cpp-一个微小的系统调用跟踪程序和调试器实现"的项目,显然是一个使用C++语言实现的简易版strace...
在汇编语言中,子程序和系统调用是两个重要的概念,它们允许程序员组织代码并利用操作系统提供的服务。 **子程序设计**是指将一段重复使用的代码封装成独立的程序单元,以便在需要时通过调用来执行。子程序可以提高...
DLL是Windows操作系统中的一种共享库,可以被多个程序同时调用。 3. **在易语言中调用**:在易语言程序中,使用“外部调用”指令引用DLL中的函数。需要指定函数名、参数类型、返回值类型,以及DLL文件的路径。 4. ...
在IT领域,Web调用本地程序是一种常见的技术需求,它允许网页通过某种方式与用户的本地计算机进行交互,执行特定的任务。这种技术广泛应用于自动化工作流程、远程服务支持、软件更新等场景。本示例提供了实现这一...
系统调用是一种特殊的子程序,由操作系统内核提供,用户程序通过特定的接口(通常在C语言中是`syscall()`函数)调用。当执行系统调用时,处理器会切换到内核模式,执行相应的内核代码,然后返回到用户模式,确保了...
"ICT程序调用系统"是信息技术(ICT)领域的一个关键组件,主要应用于测试行业中。这个系统设计的目的是为了高效、安全地在服务器端执行测试程序。在传统的测试流程中,选择正确的程序进行调用可能会出现人为错误,这...