subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。
Popen 是 subprocess的核心,子进程的创建和管理都靠它处理。
subprocess模块定义了一个类: Popen
class Popen(object):
""" Execute a child program in a new process.
For a complete description of the arguments see the Python documentation.
Arguments:
args: A string, or a sequence of program arguments.
bufsize: supplied as the buffering argument to the open() function when
creating the stdin/stdout/stderr pipe file objects
executable: A replacement program to execute.
stdin, stdout and stderr: These specify the executed programs' standard
input, standard output and standard error file handles, respectively.
preexec_fn: (POSIX only) An object to be called in the child process
just before the child is executed.
close_fds: Controls closing or inheriting of file descriptors.
shell: If true, the command will be executed through the shell.
cwd: Sets the current directory before the child is executed.
env: Defines the environment variables for the new process.
universal_newlines: If true, use universal line endings for file
objects stdin, stdout and stderr.
startupinfo and creationflags (Windows only)
restore_signals (POSIX only)
start_new_session (POSIX only)
pass_fds (POSIX only)
encoding and errors: Text mode encoding and error handling to use for
file objects stdin, stdout and stderr.
Attributes:
stdin, stdout, stderr, pid, returncode
"""
_child_created = False # Set here since __del__ checks it
def __init__(self, args, bufsize=-1, executable=None,
stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
shell=False, cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0,
restore_signals=True, start_new_session=False,
pass_fds=(), *, encoding=None, errors=None):
"""Create new Popen instance."""
常用参数:
一个简单示例,命令行执行pip
import subprocess
p = subprocess.Popen('pip -V',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
# 输出stdout
print(p.communicate()[0])
得到结果是byte类型的
b'pip 21.1.2 from e:\\python36\\lib\\site-packages\\pip (python 3.6)\r\r\n'
于是可以添加encoding参数utf-8
import subprocess
p = subprocess.Popen('pip -V',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
encoding='utf-8'
)
# 输出stdout
print(p.communicate()[0])
此时输出
pip 21.1.2 from e:\python36\lib\site-packages\pip (python 3.6)
如果输出有中文,会出现解码异常
输入java,正常情况是可以输出中文的
import subprocess
p = subprocess.Popen('java',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
encoding='utf-8'
)
# 输出stdout
print(p.communicate()[0])
但是运行结果就会解码异常
Traceback (most recent call last):
File "D:/tests.py", line 44, in
print(p.communicate()[0])
File "E:\python36\lib\subprocess.py", line 830, in communicate
stdout = self.stdout.read()
File "E:\python36\lib\codecs.py", line 321, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd3 in position 0: invalid continuation byte
原因是windows系统编码是gb2312
知道windows系统的编码后,设置对应的编码,就可以正常解码了
import subprocess
p = subprocess.Popen('java',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
encoding='gb2312'
)
# 输出stdout
print(p.communicate()[0])
得到
用法: java [-options] class [args...]
(执行类)
或 java [-options] -jar jarfile [args...]
(执行 jar 文件)
其中选项包括:
-d32 使用 32 位数据模型 (如果可用)
-d64 使用 64 位数据模型 (如果可用)
-server 选择 "server" VM
默认 VM 是 server.
也可以在拿到输出结果后decode解码
import subprocess
p = subprocess.Popen('java',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
# 输出stdout
result = p.communicate()[0]
print(result.decode('gb2312'))
接下来写一小段python代码,看执行结果
# xx.py
print("hello world! 这段包含了中文")
使用subprocess.Popen执行,需设置encoding=‘utf-8’
import subprocess
p = subprocess.Popen(['python', 'xx.py'],
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
encoding='utf-8'
)
# 输出stdout
print(p.communicate()[0])
运行结果
hello world! 这段包含了中文
如果python代码有语法异常
# xx.py
print("hello world! 这段包含了中文"x)
此时是可以输出异常内容的
File "xx.py", line 1
print("hello world! 这段包含了中文"x)
^
SyntaxError: invalid syntax
Popen 对象方法用到的几个方法
其它方法参考菜鸟教程https://www.runoob.com/w3cnote/python3-subprocess.html