Python模块 - subprocess

Posted 慕沁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python模块 - subprocess相关的知识,希望对你有一定的参考价值。

subprocess – 创建附加进程 
subprocess模块提供了一种一致的方法来创建和处理附加进程,与标准库中的其它模块相比,提供了一个更高级的接口。用于替换如下模块: 
os.system() , os.spawnv() , os和popen2模块中的popen()函数,以及 commands().

1. 运行外部命令 
subprocess.call(command) 方法 
subprocess的call方法可以用于执行一个外部命令,但该方法不能返回执行的结果,只能返回执行的状态码: 成功(0) 或 错误(非0) 
call()方法中的command可以是一个列表,也可以是一个字符串,作为字符串时需要用原生的shell来执行:

import subprocess
#执行 df -hl 命令
#方法1:
>>> subprocess.call([ls,-l])
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
0
#方法2:
>>> subprocess.call("ls -l",shell=True)
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp

如上实例所示,虽然我们能看到执行的结果,但实际获取的值只是状态码

>>> output = subprocess.call("ls -l",shell=True)
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
>>> print(output)
0

2. 错误处理 

subprocess.check_call() 方法 
我们说过call执行返回一个状态码,我们可以通过check_call()函数来检测命令的执行结果,如果不成功将返回 subprocess.CalledProcessError 异常

>>> try:
        subprocess.check_call("ls -t", shell=True)
    except subprocess.CalledProcessError as err:
        print("Command Error") 

/bin/sh: lt: command not found
Command Error

3. 捕获输出结果 
subprocess.check_output() 方法

call()方法启动的进程,其标准输入输出会绑定到父进程的输入和输出。调用程序无法获取命令的输出结果。但可以通过check_output()方法来捕获输出。

# 以下测试为python3.4下运行结果
>>> output=subprocess.check_output("ls -l",shell=True)
>>> output
btotal 8\ndrwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem\ndrwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp\n
>>> print(output.decode(utf-8))
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp

 

以下例子将chek_output()方法执行命令异常时的错误捕获,而避免输出到控制台.

try:
    output = subprocess.check_output("lT -l", shell=True, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as err:
    print("Command Error", err)

# 执行结果
Command Error Command lT -l returned non-zero exit status 127

 

 

直接处理管道 

subprocess.Popen()方法

函数call(), check_call() 和 check_output() 都是Popen类的包装器。直接使用Popen会对如何运行命令以及如何处理其输入输出有更多控制。如通过为stdin, stdout和stderr传递不同的参数。

  1. 与进程的单向通信 
    通过Popen()方法调用命令后执行的结果,可以设置stdout值为PIPE,再调用communicate()获取结果 
    返回结果为tuple. 在python3中结果为byte类型,要得到str类型需要decode转换一下

输出结果(读)

# 直接执行命令输出到屏幕
>>> subprocess.Popen("ls -l",shell=True)
<subprocess.Popen object at 0x7febd4175198>
>>> total 12
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
-rw-rw-r-- 1 ws ws    8 Feb 25 10:38 test
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp

# 不输出到屏幕,输出到变量
>>> proc = subprocess.Popen([echo,"Stdout"],stdout=subprocess.PIPE)
# communicate返回标准输出或标准出错信息
>>> stdout_value = proc.communicate()
>>> stdout_value
(b"Stdout"\n, None)

>>> proc = subprocess.Popen([ls,-l],stdout=subprocess.PIPE)
>>> stdout_value = proc.communicate()
>>> stdout_value
(btotal 8\ndrwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem\ndrwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp\n, None)
>>>
>>> print((stdout_value[0]).decode(utf-8))
total 8
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp

#将结果输出到文件
>>> file_handle = open("/home/ws/t.log",w+)
>>> subprocess.Popen("ls -l",shell=True,stdout=file_handle)
t.log:
drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
-rw-rw-r-- 1 ws ws    8 Feb 25 10:38 test
-rw-rw-r-- 1 ws ws    0 Feb 25 11:24 t.log
drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp

 

2 与进程的双向通信

>>> proc = subprocess.Popen(cat, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
>>> msg = Hello world.encode(utf-8)
# 写入到输入管道
>>> proc.stdin.write(msg)
11
>>> stdout_value = proc.communicate()
>>> stdout_value
(bHello world, None)

# 在需要进行相互交互的输入输出过程也可以使用shtin来实现
# 以下实现打开python3的终端,执行一个print命令
>>>proc = subprocess.Popen([python3],stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,)
>>>proc.stdin.write(print("helloworld").encode(utf-8))
>>>out_value,err_value=proc.communicate()
>>>print(out_value)
>>> print(out_value)
bhelloworld\n
>>> print(err_value)
b‘‘

 

Popen.communicate()方法用于和子进程交互:发送数据到stdin,并从stdout和stderr读数据,直到收到EOF。等待子进程结束。

捕获错误输出

>>> proc = subprocess.Popen([python3],stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,)
>>> proc.stdin.write(print "helloworld".encode(utf-8))
18
>>> out_value,err_value=proc.communicate()
>>> out_value
b‘‘
>>> print(err_value.decode(utf-8))
  File "<stdin>", line 1
    print "helloworld"
                     ^
SyntaxError: Missing parentheses in call to print

 

Popen其它方法
  1. Popen.pid 查看子进程ID
  2. Popen.returncode 获取子进程状态码,0表示子进程结束,None未结束

    在使用Popen调用系统命令式,建议使用communicate与stdin进行交互并获取输出(stdout),这样能保证子进程正常退出而避免出现僵尸进程。看下面例子

>>> proc = subprocess.Popen(ls -l, shell=True, stdout=subprocess.PIPE)
# 当前子进程ID
>>> proc.pid
28906
# 返回状态为None,进程未结束
>>> print(proc.returncode)
None
# 通过communicate提交后
>>> out_value = proc.communicate()
>>> proc.pid
28906
# 返回状态为0,子进程自动结束
>>> print(proc.returncode)
0

 










以上是关于Python模块 - subprocess的主要内容,如果未能解决你的问题,请参考以下文章

使用 subprocess 模块是不是会释放 python GIL?

python常用代码片段总结

python模块之subprocess模块, struct模块

Python模块 - subprocess

python的subprocess模块

python模块--subprocess