如果你是一名Unix/Linux系统管理员,那么对进程进行处理将会是工作的主要内容。你需要知道启动脚本、运行等级、守护进程、长时间运行的进程以及一大堆相关问题。所幸的是,Python处理进程相当容易。从Python2.4开始,Subprocess已经成为一站式模块,允许你派生出新的进程,并且与标准输入、标准输出以及标准错误输出进行会话。与进程会话是处理进程的一方面,理解如何部署和管理长时间运行的进程也是很重要的。
子进程
Python的Subprocess或许是单一的最重要的模块,它对于shelling out具有统一API。Python中的子进程负责处理下列事物:派生新的进程连接标准输入、连接标准输出、连接错误流、侦听返回码。子进程的一个简单示例:
import subprocess
subprocess.call(['df','-k'], shell = True)
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False):父进程等待子进程完成,返回执行状态码。shell = True表示在shell中执行命令,不要将stdout=PIPE或者stdin=PIPE用于该函数,否则可能会因子进程大量输出而导致死锁。
错误处理
try:
subprocess.check_call(['false'])
except subprocess.CalledProcessError as err:
print 'ERROR:', err
Subprocess捕获标准输出
某些情况下只对系统调用感兴趣,而不关心标准输出。在这种情况下,经常需要禁止Subprocess.call的标准输出,只需将输出定位到/dev/null中即可:
import subprocess
subprocess.call("ping -c 3 www.baidu.com", shell = True, stdout = open('/dev/null'), stderr = subprocess.STDOUT)
如果对shell命令的输出不感兴趣,只是希望程序被运行,可典型的使用Subprocess.call,如果需要得到子进程的运行结果,则可以用subprocess.Popen。在subprocess.call与subprocess.Popen之间,存在一个非常大的差异。subprocess.call会封锁对时间的等待(即会卡住等待子进程运行结束),而subprocess.Popen不会。
p = subprocess.Popen('df -h", shell = True, stdout = subprocess.PIPE)
out = p.stdout.read()
print out
try:
p = subporcess.check_output(['du -sh','/home/'], shell = True)
print p
except subprocess.CalledProcessError as err:
print 'ERROR:',err
使用Subprocess与标准输入进行通信
p = subprocess.Popen("wc -c", shell = True, stdin=subprocess.PIPE)
p.communicate("charactersinword")
输出:16,具有相同功能的Bash代码为:
$ echo charactersinword | wc -c
p.communicate会一直等到进程退出,并将标准输出和标准错误输出返回,这样就可以得到子进程的输出了,另一个例子为:p = subprocess.Popen('ls', shell = True, stdout = subprocess.PIPE)
stdoutput,stderrput = p.communicate('/home/zoer')
print stdoutput
print stderrput
在Bash中可以用管道连接多个命令,比如:cat /etc/passwd | grep 0:0 | cut -d ':' -f 7
p1 = subprocess.Popen("cat /etc/passwd", shell = True, stdout = subprocess.PIPE)
p2 = subprocess.Popen("grep 0:0", shell = True, stdin = p1.stdout, stdout = subprocess.PIPE)
p3 = subprocess.Popen("cut -d ':' -f 7", shell = True, stdin = p2.stdout, stdout = subprocess.PIPE)
print p3.stdout.read()
- Popen.poll():检查子进程是否结束,设置并返回return code属性
- Popen.wait(): 等待子进程结束,设置并返回return code属性
- Popen.communicate(input=None): 与子进程进行交互,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。
- Popen.send_signal(signal): 向子进程发送信号
- Popen.terminate(): 停止(stop)子进程
- Popen.kill(): 杀死(kill)子进程
- Popen.pid: 获取子进程的ID
- Popen.returncode: 获取返回值,如果进程还没结束,就返回None