• subprocess模块


      需要通过Python去执行一条系统命令或脚本,系统的shell命令是独立于你的python进程之外的,每执行一条命令,就是发起一个新进程,通过python调用系统命令或脚本的模块在python2有os.system。

      执行返回命令执行状态,利用echo $?  查看到返回值‘0’

    >>> import os
    >>> os.system('uname -a')
    Darwin MacBook-Pro.local 17.2.0 Darwin Kernel Version 17.2.0: Fri Sep 29 18:27:05 PDT 2017; root:xnu-4570.20.62~3/RELEASE_X86_64 x86_64
    0

      python2中除了os.system可以调用系统命令,commands,popen2等也可以,比较乱。于是官方在Python3推出了subprocess,目地是提供统一的模块来实现对系统命令或脚本的调用。

    一、subprocess.run()方法

      subprocess.run(*popenargs, input=None, timeout=None, check=False, **kwargs)

      首先注意run方法执行结果,有stdout、args、returncode这三个属性。

    >>> import subprocess
    >>> a = subprocess.run(['du', '-sh'])
     24K    .
    >>> a.stdout   # 拿到标准输出结果
    >>> a.args      # 拿到标准输出命令
    ['du', '-sh']
    >>> a.returncode    # 拿到标准输出返回值
    0

      标准写法:subprocess.run(['df', '-h'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)

    >>> a = subprocess.run(['ls', '-lrt'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    >>> a.stdout    # 标准输出
    b'total 48
    -rw-r--r--  1 hqs  staff     51  4 12 16:10 __init__.py
    -rw-r--r--  1 hqs  staff  16790  4 17 22:38 ftp_client.py
    '
    >>> a.stderr    # 标准错误
    b''
    
    >>> a = subprocess.run(['df', '-sdfh'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    >>> a.stderr
    b'df: illegal option -- s
    usage: df [-b | -H | -h | -k | -m | -g | -P] [-ailn] [-T type] [-t] [filesystem ...]
    '
    >>> a.stdout
    b''

      运用管道借用操作系统内存,实现Python和shell内存交互。拿到shell命令执行结果。

      带管道符的情况,不要用列表(解析不了);

      shell=True不做解析直接把整个命令交给shell处理;

      check=True有错误将直接提示报错。不加的话不提示报错,需要用stderr查看错误。

    >>> a = subprocess.run('df -h | grep disk1',stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
    >>> a.stdout
    b'/dev/disk1s1   233Gi   62Gi  168Gi    28%  871372 9223372036853904435    0%   /
    /dev/disk1s4   233Gi  3.0Gi  168Gi     2%       3 9223372036854775804    0%   /private/var/vm
    '
    
    >>> a = subprocess.run(['df','-ususidih'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)
    提示出现CalledProcessError报错

    二、subprocee.CALL方法

      subprocess.call(*popenargs, timeout=None, **kwargs)

      应用列表执行命令主要有call()方法和check_call()方法。

      应用列表执行命令,并返回结果:check_output()方法。

      应用字符串执行命令主要有getstatusoutput()方法和getoutput()方法。

    # 执行命令,返回命令执行状态, 0或非0
    >>> retcode = subprocess.call(["ls", "-l"])
    total 0
    drwx------+  9 huangqiushi  staff   288  3  2 13:32 Desktop
    drwx------+  4 huangqiushi  staff   128  3  1 08:17 Documents
    ...
    drwxr-xr-x   7 huangqiushi  staff   224  3  2 20:26 PycharmProjects
    >>> retcode
    0
    
    # 执行命令,如果命令结果为0,就正常返回,否则抛异常
    >>> subprocess.check_call(["ls","-l"])
    0
    
    # 字符串格式命令
    # 接收字符串格式命令,返回元组格式,第1个元素是执行状态,第2个是命令结果
    >>> subprocess.getstatusoutput('ls /bin/ls')
    (0, '/bin/ls')
    
    # 接收字符串格式命令,并返回结果(无状态)
    >>> subprocess.getoutput('ls /bin/ls')
    '/bin/ls'
    
    # 执行命令,并返回结果(注意返回结果,不是打印)
    >>> res = subprocess.check_output(['du','-sh'])
    >>> res
    b' 27G	.
    '

    三、subprocess.Popen()方法

      Popen方法是最基础的方法,是run()方法和call()方法的底层封装。

    常用参数:
        args:shell命令,可以是字符串或者序列类型(如:list,元组)
        stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
        preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
        shell:shell=True的意思是这条命令直接交给系统去执行,不需要python负责解析
        cwd:用于设置子进程的当前目录
        env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
    

      Popen发起一个新进程不影响主程序,run是当前进程执行,Popen是后台执行。

    1、Popen调用后的返回对象

      Popen调用后会返回一个对象,可以通过这个对象拿到命令执行结果或状态等,该对象有以下方法:

    def sayhi():
        print('run...hahah')
    a = subprocess.Popen('echo $PWD;sleep 2',shell=True,cwd="/tmp",stdout=subprocess.PIPE,preexec_fn=sayhi)
    a.poll()  # 检查子程序是否终止,返回返回值
    a.wait()  # 等待子程序终止,返回返回值
    a.terminate()  # 终止所启动的进程
    a.kill()    # 杀死所启动的进程
    a.communicate()    # 与启动的进程交互,发送数据到stdin,从stdout接收输出,然后等待任务结束
    a.send_signal(signal.xxx)   # 发送系统信号
    a.pid # 拿到所启动进程的进程号

    2、管道操作

    >>> def sayhi():
    ...         print('run...hahah')
    >>> a = subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE,preexec_fn=sayhi)
    >>> a.stdout  
    <_io.BufferedReader name=3>
    >>> a.stdout.read() 
    b'run...hahah
    '
    # cwd设置当前目录
    >>> a = subprocess.Popen('echo $PWD;sleep 2',shell=True,cwd="/tmp",stdout=subprocess.PIPE,preexec_fn=sayhi)
    >>> a.stdout.read()
    b'run...hahah
    /private/tmp
    ' 

    3、pid()方法使用

      注意terminate()kill()方法的区别:终止和杀死

    >>> a = subprocess.Popen('sleep 100',shell=True,stdout=subprocess.PIPE) 
    >>> a.pid
    14939
    >>> a.terminate()  # 停掉不强制,进程没有停掉
    
    >>> a = subprocess.Popen('for i in $(seq 1 100);do sleep 1;echo $i >> /tmp/sleep.log;done',shell=True,stdout=subprocess.PIPE)
    >>> a.pid
    15056
    >>> a.kill()   # 强制杀死进程

    4、communicate()方法

      与启动的进程交互,发送数据到stdin,并从stdout接收输出,然后等待任务结束需要用bytes进行交互、且只能交互一次。

    >>> a = subprocess.Popen('python3 guessAge.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE,shell=True)
    >>> a.communicate(b'1234')  # 需要和bytes进行交互
    (b'guess age: try smaller,you have 3 chance
    
    guess age: ', b'Traceback (most recent call last):
    
      File "guessAge.py", line 19, in <module>
    
          guess_age = int(input("guess age: "))
    
          EOFError: EOF when reading a line
    ')

    5、send_signal()方法发送系统信号

    import signal
    a = subprocess.Popen('sleep 100',stdout=subprocess.PIPE,shell=True)
    a.send_signal(signal.SIGKILL)

     

  • 相关阅读:
    记录一下思源服务端的安装过程
    在Github上键政,然后被封号
    使用Aspnet_regiis加密web.config binzi
    策略模式
    Android Ril 分析
    20192422李俊洁 汇编语言程序设计1~4章学习笔记
    阿里云服务器如何配置开放端口
    关于DIFF插件的使用
    Python3 web开发中几种密码加密方式
    中间件安装——用Docker在CentOS7部署MongoDB服务
  • 原文地址:https://www.cnblogs.com/xiugeng/p/8874227.html
Copyright © 2020-2023  润新知