zoukankan      html  css  js  c++  java
  • python subprocess模块

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

    os.system()  结果输出在终端上,会返回执行命令的状态码,我们可以用变量来接收
    >>> import os
    >>> os.system('hostname')
    mysql
    0
    >>> 

    返回的0就是这个linux命令执行状态,0就是代表命令返回成功,命令执行不成功就是非0

    这个命令执行状态 相当于echo $?

    我们看到把命令 赋值给a a变量最后返回是0,返回是命令执行状态,不是命令的结果

    >>> a = os.system('df')
    文件系统             1K-块      已用      可用 已用% 挂载点
    /dev/sda5              5039616   2757016   2026600  58% /
    tmpfs                   135720         0    135720   0% /dev/shm
    /dev/sda1                99150     27098     66932  29% /boot
    /dev/sda8            481685144   1082644 456134276   1% /data
    /dev/sda6              5039616    141080   4642536   3% /home
    /dev/sda2             10079084   2660636   6906448  28% /usr
    /dev/sda3             10079084    274856   9292228   3% /var
    >>> a
    0

    这个通过os.system()是拿不到命令结果的,但我们可以通过os.popen() 可以拿到

    os.popen()  他的原理是在内存打开一个临时文件把 命令结果存到这个文件里,把文件内容读出来 相当于文件操作

    >>> os.popen('df')
    <os._wrap_close object at 0x7f36e2410518>

    拿到结果了

    >>> f = os.popen('df')
    >>> f
    <os._wrap_close object at 0x7f36e2373390>
    >>> f.read()
    '文件系统	         1K-块      已用      可用 已用% 挂载点
    /dev/sda5              5039616   2757016   2026600  58% /
    tmpfs                   135720         0    135720   0% /dev/shm
    /dev/sda1                99150     27098     66932  29% /boot
    /dev/sda8            481685144   1082644 456134276   1% /data
    /dev/sda6              5039616    141080   4642536   3% /home
    /dev/sda2             10079084   2660636   6906448  28% /usr
    /dev/sda3             10079084    274864   9292220   3% /var
    '

    在read() 没有了

    >>> f.read()
    ''

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

    python3没有了commands模块 , subprocess模块就是为了替换commands模块 os.system 这些模块

     subprocess模块可以调用操作系统命令,python在linux可以执行shell命令,subprocess 每执行一条命令,

    会开启一个子进程(即shell)来执行命令,相当于每执行一条命令,打开一个独立程序窗口,这个就是进程:

    subprocess模块

    三种执行命令的方法

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

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

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

    subprocess.run run方法

    返回一个对象,执行一条命令返回一个对象,通过对象拿到命令结果

    加上列表意思,里面输入命令参数传给subprocess ,subprocess会帮你拼接成完整的shell命令

    >>> import subprocess
    >>> 
    >>> subprocess.run(['df','-h'])
    文件系统          容量  已用  可用 已用%% 挂载点
    /dev/sda5             4.9G  2.7G  2.0G  58% /
    tmpfs                 133M     0  133M   0% /dev/shm
    /dev/sda1              97M   27M   66M  29% /boot
    /dev/sda8             460G  1.1G  436G   1% /data
    /dev/sda6             4.9G  138M  4.5G   3% /home
    /dev/sda2             9.7G  2.6G  6.6G  28% /usr
    /dev/sda3             9.7G  269M  8.9G   3% /var
    CompletedProcess(args=['df', '-h'], returncode=0)
    >>> a
    CompletedProcess(args=['df', '-h'], returncode=0)

    通过对象去拿结果

    # 返回命令返回状态
    >>> a.returncode
    0
    
    # 返回命令参数
    >>> a.args 
    ['df', '-h']

    python怎么去拿结果?


    标准写法
    subprocess.run(['df','-h'],stderr=subprocess.PIPE,stdout=subprocess.PIPE,check=True)
    stderr是标准错误,输出错误信息。 stdout是标准输出,输出正确信息。
    PIPE是一个管道,
    管道相当于建立一个进程执行命令,命令结果通过管道返回python的标准输出,如果命令执行错误了,
    管道返回到标准错误

    管道就是操作系统,借操作系统内存把管道拿出来

    # 把执行命令结果存到管道里
    >>> a = subprocess.run(['df','-h'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    
    # 把结果读出来,标准输出
    >>> a.stdout 
    b'Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda5             4.9G  2.7G  2.0G  58% /
    tmpfs                 133M     0  133M   0% /dev/shm
    /dev/sda1              97M   27M   66M  29% /boot
    /dev/sda8             460G  1.1G  436G   1% /data
    /dev/sda6             4.9G  138M  4.5G   3% /home
    /dev/sda2             9.7G  2.6G  6.6G  28% /usr
    /dev/sda3             9.7G  269M  8.9G   3% /var
    '
    
    #没有错误信息,标准错误
    >>> a.stderr
    b''

    check=True 如果命令返回一个非0的执行状态,给程序报错

    我们输入一个没有的参数
    >>> a = subprocess.run(['df','-sssh'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,)
    >>> a.stdout
    b''
    
    # 出错 
    >>> a.stderr
    b"df: invalid option -- 's'
    Try `df --help' for more information.
    "

    出错,但整个程序没有报错

    加上check=True 程序直接报错了  返回非0 命令执行状态
    >>> a = subprocess.run(['df','-sssh'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/local/python3.6/lib/python3.6/subprocess.py", line 418, in run
        output=stdout, stderr=stderr)
    subprocess.CalledProcessError: Command '['df', '-sssh']' returned non-zero exit status 1.
    
    
    
    现在我们执行一些复杂的命令, 用linux命令的管道 + grep 过滤一些信息出来
    通过操作系统的管道,交给grep 过滤一些信息

    [root@mysql ~]# df -h|grep sda3
    /dev/sda3             9.7G  269M  8.9G   3% /var
    
    
    
    在subprocess.run()执行这条命令,
    报错了
    >>> a = subprocess.run(['df','-h','|','sda3'],stderr=subprocess.PIPE,stdout=subprocess.PIPE,check=True)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/local/python3.6/lib/python3.6/subprocess.py", line 418, in run
        output=stdout, stderr=stderr)
    subprocess.CalledProcessError: Command '['df', '-h', '|', 'sda3']' returned non-zero exit status 1.
    
    
    
    通过subprocess 执行一个 涉及到管道|的命令需要这样写 
    需要不写列表了,然后加上
    shell=True
    #shell=True的意思是这条命令不需要帮忙拼接参数,直接交给系统去执行shell命令
     

    可以了

    >>> a = subprocess.run('df -h|grep sda3',stderr=subprocess.PIPE,stdout=subprocess.PIPE,shell=True)
    >>> a.stderr
    b''
    >>> a.stdout
    b'/dev/sda3             9.7G  269M  8.9G   3% /var
    '
    >>> 
    
    
    

    subprocess.call() 方法 介绍 

    和run方法一样的

    call() 执行命令,返回命令执行状态 , 0 or 非0

    #执行命令,返回命令执行状态 , 0 or 非0
    
    >>> subprocess.call(['ls','-la'])
    total 240
    dr-xr-x---.  8 root root  4096 Feb 26 23:33 .
    dr-xr-xr-x. 24 root root  4096 Feb 26 06:39 ..
    -rw-------.  1 root root  1080 Oct  6 01:40 anaconda-ks.cfg
    -rw-------.  1 root root  5449 Feb 26 23:33 .bash_history
    -rw-r--r--.  1 root root    18 May 20  2009 .bash_logout
    -rw-r--r--.  1 root root   176 May 20  2009 .bash_profile
    -rw-r--r--.  1 root root   176 Sep 23  2004 .bashrc
    -rw-r--r--.  1 root root 15624 Feb 24 06:39 blog.sql
    drwx------.  3 root root  4096 Feb 26 07:37 .cache
    -rw-r--r--.  1 root root   100 Sep 23  2004 .cshrc
    -rwxr-xr-x.  1 root root   118 Feb 26 21:29 getMemory.py
    -rw-r--r--.  1 root root  7730 Oct  6 01:40 install.log
    -rw-r--r--.  1 root root  3384 Oct  6 01:38 install.log.syslog
    -rw-------.  1 root root 43579 Feb 23 09:25 .mysql_history
    -rw-r--r--.  1 root root 13811 Nov 22 09:32 oot
    drwxr-xr-x.  2 root root  4096 Nov 15 02:09 .oracle_jre_usage
    drwxr-----.  3 root root  4096 Oct  6 02:09 .pki
    -rw-------.  1 root root   694 Feb 26 23:29 .python_history
    drwxr-xr-x.  3 root root  4096 Nov 19 01:32 .subversion
    -rw-r--r--.  1 root root   129 Dec  4  2004 .tcshrc
    -rw-------.  1 root root  6578 Feb 26 23:33 .viminfo
    0
    
    >>> a = subprocess.call(['ls','-la'])
    total 240
    dr-xr-x---.  8 root root  4096 Feb 26 23:33 .
    dr-xr-xr-x. 24 root root  4096 Feb 26 06:39 ..
    -rw-------.  1 root root  1080 Oct  6 01:40 anaconda-ks.cfg-rw-------.  1 root root  5449 Feb 26 23:33 .bash_history
    -rw-r--r--.  1 root root    18 May 20  2009 .bash_logout
    -rw-r--r--.  1 root root   176 May 20  2009 .bash_profile
    -rw-r--r--.  1 root root   176 Sep 23  2004 .bashrc
    -rw-r--r--.  1 root root 15624 Feb 24 06:39 blog.sql
    drwx------.  3 root root  4096 Feb 26 07:37 .cache-rw-r--r--.  1 root root  7730 Oct  6 01:40 install.log
    -rw-r--r--.  1 root root  3384 Oct  6 01:38 install.log.syslog
    -rw-------.  1 root root 43579 Feb 23 09:25 .mysql_history
    -rw-r--r--.  1 root root 13811 Nov 22 09:32 oot
    drwxr-xr-x.  2 root root  4096 Nov 15 02:09 .oracle_jre_usage
    drwxr-----.  3 root root  4096 Oct  6 02:09 .pki
    -rw-------.  1 root root   694 Feb 26 23:29 .python_history
    drwxr-xr-x.  3 root root  4096 Nov 19 01:32 .subversion
    -rw-r--r--.  1 root root   129 Dec  4  2004 .tcshrc
    -rw-------.  1 root root  6578 Feb 26 23:33 .viminfo
    >>> a
    0
    
    
    subprocess.check_call
    用法和call方法一样的,不同的是,执行命令,如果命令结果为0,就正常返回,否则抛异常,
    会抛出 CalledProcessError 异常,我们可以根据这个异常去决定需要做什么

    >>> subprocess.check_call(['df','-h'])
    Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda5             4.9G  2.7G  2.0G  58% /
    tmpfs                 133M     0  133M   0% /dev/shm
    /dev/sda1              97M   27M   66M  29% /boot
    /dev/sda8             460G  1.1G  436G   1% /data
    /dev/sda6             4.9G  138M  4.5G   3% /home
    /dev/sda2             9.7G  2.6G  6.6G  28% /usr
    /dev/sda3             9.7G  269M  8.9G   3% /var
    0
    >>> a = subprocess.check_call(['df','-h'])
    Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda5             4.9G  2.7G  2.0G  58% /
    tmpfs                 133M     0  133M   0% /dev/shm
    /dev/sda1              97M   27M   66M  29% /boot
    /dev/sda8             460G  1.1G  436G   1% /data
    /dev/sda6             4.9G  138M  4.5G   3% /home
    /dev/sda2             9.7G  2.6G  6.6G  28% /usr
    /dev/sda3             9.7G  269M  8.9G   3% /var
    >>> a
    0
    >>> a = subprocess.check_call(['df','-hd'])
    df: invalid option -- 'd'
    Try `df --help' for more information.
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/local/python3.6/lib/python3.6/subprocess.py", line 291, in check_call
        raise CalledProcessError(retcode, cmd)
    subprocess.CalledProcessError: Command '['df', '-hd']' returned non-zero exit status 1.
    
    
    subprocess.getstatusoutput() 方法
    接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果 

    >>> subprocess.getstatusoutput('df -h')
    (0, 'Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda5             4.9G  2.7G  2.0G  58% /
    tmpfs                 133M     0  133M   0% /dev/shm
    /dev/sda1              97M   27M   66M  29% /boot
    /dev/sda8             460G  1.1G  436G   1% /data
    /dev/sda6             4.9G  138M  4.5G   3% /home
    /dev/sda2             9.7G  2.6G  6.6G  28% /usr
    /dev/sda3             9.7G  269M  8.9G   3% /var')
    
    
    
    subprocess.getoutput() 方法
    接收字符串格式命令,并返回结果,只返回结果

    >>> subprocess.getoutput('df -h')
    'Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda5             4.9G  2.7G  2.0G  58% /
    tmpfs                 133M     0  133M   0% /dev/shm
    /dev/sda1              97M   27M   66M  29% /boot
    /dev/sda8             460G  1.1G  436G   1% /data
    /dev/sda6             4.9G  138M  4.5G   3% /home
    /dev/sda2             9.7G  2.6G  6.6G  28% /usr
    /dev/sda3             9.7G  269M  8.9G   3% /var'
    
    
    
    
    subprocess.check_output() 方法
    执行命令,并返回结果,注意是返回结果,不是打印,下例结果返回给res
    >>> subprocess.check_output(['df', '-h'])
    b'Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda5             4.9G  2.7G  2.0G  58% /
    tmpfs                 133M     0  133M   0% /dev/shm
    /dev/sda1              97M   27M   66M  29% /boot
    /dev/sda8             460G  1.1G  436G   1% /data
    /dev/sda6             4.9G  138M  4.5G   3% /home
    /dev/sda2             9.7G  2.6G  6.6G  28% /usr
    /dev/sda3             9.7G  269M  8.9G   3% /var
    '
    >>> 
    >>> res = subprocess.check_output(['df', '-h'])
    >>> res
    b'Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda5             4.9G  2.7G  2.0G  58% /
    tmpfs                 133M     0  133M   0% /dev/shm
    /dev/sda1              97M   27M   66M  29% /boot
    /dev/sda8             460G  1.1G  436G   1% /data
    /dev/sda6             4.9G  138M  4.5G   3% /home
    /dev/sda2             9.7G  2.6G  6.6G  28% /usr
    /dev/sda3             9.7G  269M  8.9G   3% /var
    '
    
    

    Popen()方法

    常用参数:

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

    subprocess.Popen() :用于执行 shell 命令,结果返回三个对象,分别是标准输入,标准输出,标准错误输出


    Popen调用后会返回一个对象,可以通过这个对象拿到命令执行结果或状态等,该对象有以下方法
    poll()
    检查命令有没有执行结束,执行结束返回命令执行状态
    >>> a = subprocess.Popen('df -h',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    >>> a
    <subprocess.Popen object at 0x7f54f190de10>
    
    # poll() 返回命令执行状态
    >>> a.poll()
    0

    下面这2条语句执行会有什么区别?
    a=subprocess.run('sleep 10',shell=True,stdout=subprocess.PIPE)
    a=subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)
    
    

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

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

     

     
  • 相关阅读:
    Python GIL-------全局解释器锁
    JavaScript简介
    MongoDB查询
    创建、更新和删除文档
    MongoDB基础知识
    Linux安装mysql
    函数、变量、参数
    循环语句
    控制语句
    集合
  • 原文地址:https://www.cnblogs.com/mingerlcm/p/10444289.html
Copyright © 2011-2022 走看看