• python笔记65


    前言

    subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。
    Popen 是 subprocess的核心,子进程的创建和管理都靠它处理。

    subprocess.Popen

    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."""
    

    常用参数:

    • args:shell命令,可以是字符串或者序列类型(如:str, list,元组)
    • bufsize:缓冲区大小。当创建标准流的管道对象时使用,默认-1。
      0:不使用缓冲区
      1:表示行缓冲,仅当universal_newlines=True时可用,也就是文本模式
      正数:表示缓冲区大小
      负数:表示使用系统默认的缓冲区大小。
    • stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
    • preexec_fn:只在 Unix 平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
    • shell:如果该参数为 True,将通过操作系统的 shell 执行指定的命令。
    • cwd:用于设置子进程的当前目录。
    • env:用于指定子进程的环境变量。如果 env = None,子进程的环境变量将从父进程中继承。
    • encoding:设置编码类型

    使用示例

    一个简单示例,命令行执行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)
    
    '
    

    于是可以添加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:python36libsite-packagespip (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 <module>
        print(p.communicate()[0])
      File "E:python36libsubprocess.py", line 830, in communicate
        stdout = self.stdout.read()
      File "E:python36libcodecs.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解码

    知道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代码,得到stdout内容

    接下来写一小段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 对象方法

    Popen 对象方法用到的几个方法

    • poll(): 检查进程是否终止,如果终止返回 returncode,否则返回 None。
    • wait(timeout): 等待子进程终止。
    • communicate(input,timeout): 和子进程交互,发送和读取数据。
    • send_signal(singnal): 发送信号到子进程 。
    • terminate(): 停止子进程,也就是发送SIGTERM信号到子进程。
    • kill(): 杀死子进程。发送 SIGKILL 信号到子进程。

    其它方法参考菜鸟教程https://www.runoob.com/w3cnote/python3-subprocess.html

  • 相关阅读:
    Docker 中 安装Redis
    k8s1.19.16 二进制安装
    K8S(kubernetes)+containerd部署指南
    npm install及其目录结构
    Caddy神奇: http服务免ssl证书改造为https
    gdb的set followforkmode child如何工作
    请求JAVA接口 一直返回 超时
    docker系列 可视化监控容器
    docker系列什么是docker
    docker系列 安装redis
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/15353481.html
Copyright © 2020-2023  润新知