当前位置:   article > 正文

Python编程之子进程管理(subprocess)详解_python subprocess 等待结束

python subprocess 等待结束

引言

在写程序时,我们无法避免需要运行外部程序,相较于功能比较简单的os.system(),更加倾向于使用subprocess模块来执行外部程序。

模块介绍

subprocess.run()

使用subprocess.run()执行命令的时候,父进程会一直等待直到子进程结束后才会继续运行父进程

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, 
          encoding=None, errors=None, text=None, env=None, universal_newlines=None, **other_popen_kwargs)

"""
参数介绍
    
    1. args: cmd命令
    2. stdin: 传递参数进来
    3. input: 传递参数进来,使用input的时候不能使用stdin
    4. stdout: 外部程序的输出,可以指定通过管道(subprocess.PIPE)
    5. stderr: 外部程序的报错输出, 可以指定通过管道(subprocess.PIPE)或者和stdout使用同一句柄(stderr=subprocess.STDOUT)
    6. capture_output: 同时获取stdout和stderr
    7. shell: 是否通过shell执行命令
    8. cwd: 命令执行的工作目录
    9. timeout: 如果超时则终止子进程,该参数被传递给Popen.communicate()
    10. check: 检查returncode是否为0,如果不为0则引发subprocess.CalledProcessError错误, 可以通过try....except...捕获
    11. encoding: 编码类型
    12. errors: 
    13. text: 可用来代替universal_newlines
    14. env: 设置环境变量
    15. universal_newlines: 返回数据以文本字符串输出,否则为二进制输出

"""
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

实例

import subprocess as sp

# 三种方式构造命令
sp.run('ls -l', shell=True)

sp.run(['ls', '-l'], shell=True)

sp.run(' '.join(['ls', '-l']), shell=True)

# 判断是否正确执行命令
sp.run('ls -l', shell=True, check=True)

# 获取命令的输出
p = sp.run('ls -l', shell=True, check=True, stdout=sp.PIPE, stderr=sp.PIPE)

print(p.stdout.read())

# 使用stdin接受数据传入
p1 = sp.run('ls -l', shell=True, check=True, stdout=sp.PIPE, stderr=sp.PIPE)

print(p1.stdout.read())

p2 = sp.run('grep lovefish', shell=True, check=True, stdin=p1.stdout, stdout=sp.PIPE, stderr=sp.PIPE)

print(p2.stdout.read())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

subprocess.Popen()

 
subprocess.Popen(args, bufsize=- 1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, 
          shell=False, cwd=None, env=None, universal_newlines=None, startupinfo=None, 
          creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, 
          group=None, extra_groups=None, user=None, umask=- 1, encoding=None, errors=None, text=None, pipesize=- 1)

"""
参数介绍

    1. args:cmd命令,字符串或者列表
    2. bufsize:0:无缓冲; 1:行缓冲,只可以在universal_newlines=True时被使用;其他正值则为缓冲区的大小;负数则为使用系统默认缓冲
    3. executable:一般不使用,用来表示shell程序
    4. stdin:传递数据进来
    5. stdout:命令的输出,可以指定通过管道输出(subprocess.PIPE)
    6. stderr:命令的报错输出,可以通过管道(subprocess.PIPE)或者和stdout使用同一句柄输出(subprocess.STDOUT)
    7. preexec_fns: 在exec之前执行
    8. close_fds:如果为真,在unix下,则关闭除0,1,2之外的文件。在windows下无法设置close_fds为真和重定向stderr和stdout
    9. shell:是否通过shell执行命令
    10. cwd:命令执行的工作目录
    11. env:设置环境变量
    12. universal_newlines:让返回数据以文本字符串输出
    13. pipesize:设置sp.PIPE的大小

函数介绍

    1. Popen.poll():检查子进程是否结束
    2. Popen.wait():等待直到子进程结束
    3. Popen.communicate():内部数据交互,将数据发送给stdin,返回stdout和stderr
    4. Popen.send_signal():发送信号给子进程
    5. Popen.terminate():终止子进程,unix下对应SIGTERM,windows下对应TerminateProcess() 
    6. Popen.kill():杀死子进程,unix下对应SIGKILL,windows下和terminate()一致

对象介绍

    1. Popen.args:命令
    2. Popen.stdout:命令的输出
    3. Popen.stderr:命令的报错输出
    4. Popen.stdin:命令接受的数据
    5. Popen.pid:子进程的ID
    6. Popen.returncode:返回值
    
"""
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

实例

import subprocess as sp

#  父进程不等待子进程
p = sp.Popen('ls -l', shell=True,  stdout=sp.PIPE, stderr=sp.PIPE)

# 父进程等待子进程结束之后再继续运行
p = sp.Popen('ls -l', shell=True,  stdout=sp.PIPE, stderr=sp.PIPE)

p.wait()

# 使用内容管理器
with Popen(["ls -l"], stdout=PIPE) as proc: 
  print(proc.stdout.read())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意

在使用管道(PIPE)输出stdout或者stderr时,请注意输出的数据量不能超过PIPE的上限,否则就会出现PIPE被阻塞,导致程序被阻塞无法继续运行,可以通过使用Popen.communicate()把stdout和stderr的输出存到内存中来缓解由于PIPE过小导致subprocess.Popen()无法继续运行程序的问题

Reference

subprocess 官方文档

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号