• 23-[模块]-subprocess模块


     1.调用系统命令

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

    >>> os.system('uname -a')
    Darwin Alexs-MacBook-Pro.local 15.6.0 Darwin Kernel Version 15.6.0: Sun Jun  4 21:43:07 PDT 2017; root:xnu-3248.70.3~1/RELEASE_X86_64 x86_64
    0
    

      

    (1)os.system

    >>> import os
    >>> os.system('df -h')
    Filesystem                                           Size  Used Avail Use% Mounted on
    C:/Program Files (x86)/cmder/vendor/git-for-windows  224G   86G  139G  39% /
    D:                                                   101G 1001M  100G   1% /d
    E:                                                   123G  129M  122G   1% /e
    F:                                                   122G  1.3G  121G   1% /f
    G:                                                   123G  3.6G  119G   3% /g
    0
    >>> os.system('uname')
    MSYS_NT-6.1-WOW
    0
    >>>

    (2)os.popen

    >>> f = os.popen('df -h')
    >>> f
    <os._wrap_close object at 0x03501750>
    >>> f.read()
    'Filesystem                                           
    Size  Used Avail Use% 
    Mounted on
    
    C:/Program Files (x86)/cmder/vendor/git-for-windows  224G   86G  139G  39% /
    
    D:
                       101G 1001M  100G   1% /d
    
    E:                                                   123G  129M  122G   1% /e
    
    F:                                                   122G  1.3G  121G   1% /f
    
    G:                                                   123G  3.6G  119G   3% /g
    '
    >>>
    >>> f.close()
    >>>
    

      

    (3)commands   #python2

    >>> import commands
    >>> commands.getstatusoutput('df -h')
    (0, 'xe6x96x87xe4xbbxb6xe7xb3xbbxe7xbbx9f      
      xe5xaexb9xe9x87x8f  xe5xb7xb2xe7x94xa8 
     xe5x8fxafxe7x94xa8 xe5xb7xb2xe7x94xa8% xe6x8cx82xe8xbdxbdxe7x82xb9
    udev         
       973M     0  973M    0% /dev
    tmpfs           199M  6.4M  192M    4% 
    /run
    /dev/sda1        21G   11G  8.8G   56% /
    tmpfs           992M  200K  992M    
    1% /dev/shm
    tmpfs           5.0M  4.0K  5.0M    1% /run/lock
    tmpfs          
     992M     0  992M    0% /sys/fs/cgroup
    tmpfs       
        199M   56K  199M    1% /run/user/1000')
    >>> 
    

      

    这条命令的实现原理是什么呢?(视频中讲,解释进程间通信的问题...)

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

    2、subprocess模块

    三种执行命令的方法

      • subprocess.run(*popenargs, input=None, timeout=None, check=False, **kwargs) #官方推荐

      • subprocess.call(*popenargs, timeout=None, **kwargs) #跟上面实现的内容差不多,另一种写法

      • subprocess.Popen() #上面各种方法的底层封装

      (1)run()方法

      功能:执行args参数所表示的命令,等待命令结束,并返回一个CompletedProcess类型对象。

    Run command with arguments and return a CompletedProcess instance.The returned instance will have attributes args,
     returncode, stdout and stderr. By default, stdout and stderr are not captured, 
    and those attributes will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.
    
    If check is True and the exit code was non-zero, it raises a CalledProcessError. 
    The CalledProcessError object will have the return code in the returncode attribute,
     and output & stderr attributes if those streams were captured.
    
    If timeout is given, and the process takes too long, a TimeoutExpired exception will be raised.
    
    The other arguments are the same as for the Popen constructor.
    >>>  import subprocess
    >>> subprocess.run(['df','-h'])
    

      

     

    标准写法

    subprocess.run(['df','-h'],stderr=subprocess.PIPE,stdout=subprocess.PIPE,check=True)
    

      

    涉及到管道|的命令需要这样写

    subprocess.run('df -h|grep disk1',shell=True) #shell=True的意思是这条命令直接交给系统去执行,不需要python负责解析
    

      

        

      (2) call()方法

    #执行命令,返回命令执行状态 , 0 or 非0
    >>> retcode = subprocess.call(["ls", "-l"])
    
    #执行命令,如果命令结果为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
    >>> res=subprocess.check_output(['ls','-l'])
    >>> res

     

      (3)Popen()方法

      常用参数:

    • args:shell命令,可以是字符串或者序列类型(如:list,元组)
    • stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
    • preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
    • shell:同上
    • cwd:用于设置子进程的当前目录
    • env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。

    下面这2条语句执行会有什么区别?

    a=subprocess.run('sleep 10',shell=True,stdout=subprocess.PIPE)
    a=subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)

    区别是Popen会在发起命令后立刻返回,而不等命令执行结果。这样的好处是什么呢?

    如果你调用的命令或脚本 需要执行10分钟,你的主程序不需卡在这里等10分钟,可以继续往下走,干别的事情,每过一会,通过一个什么方法来检测一下命令是否执行完成就好了。

      

       

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

    (1)poll()

    Check if child process has terminated. Returns returncode
    # 检查子进程是否死亡

     

    (2)wait()
    Wait for child process to terminate. Returns returncode attribute.
    

      

    (3)terminate()、kill()

    terminate()终止所启动的进程Terminate the process with SIGTERM
    
    kill() 杀死所启动的进程 Kill the process with SIGKILL
    

      

    # 向文件写入数字
    In [35]: a=subprocess.Popen('for i in $(seq 1 100);do sleep 1;echo $i >> /tmp/sleep.log;done',shell=True,stdout=subprocess.PIPE)
    
    # 文件内容
    python@ubuntu:~$ tail -f /tmp/sleep.log 
    1
    2
    3
    4
    5
    6
    
    
    In [37]: a.pid   #查看进程号
    Out[37]: 7572
    
    In [38]: a.kill()   #停止写入
    In [39]: a=subprocess.Popen('for i in $(seq 1 100);do sleep 1;echo $i >> /tmp/sleep.log;done',shell=True,stdout=subprocess.PIPE)
    
    In [40]: a.pid
    Out[40]: 7629
    
    In [41]: import signal
    In [42]: import os
    In [45]: os.kill(7629,signal.SIGTERM)

      (4)发送系统信号

    send_signal(signal.xxx)发送系统信号
    
    pid 拿到所启动进程的进程号

     

      (5)communicate()

    communicate()与启动的进程交互,发送数据到stdin,并从stdout接收输出,然后等待任务结束
    
    >>> a = subprocess.Popen('python3 guess_age.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE,shell=True)
    
    >>> a.communicate(b'22')
    
    (b'your guess:try bigger
    ', b''

      

  • 相关阅读:
    perl学习笔记三
    linux下编译C/C++
    redis学习笔记——数据类型
    redis学习笔记二
    perl学习笔记二
    hadoop实战 -- 网站日志KPI指标分析
    Java反射与动态代理
    使用maven来管理您的java项目
    使用MapReduce实现一些经典的案例
    编译本地64位版本的hadoop-2.6.0
  • 原文地址:https://www.cnblogs.com/venicid/p/8462731.html
Copyright © 2020-2023  润新知