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() '文件系统\t 1K-块 已用 可用 已用% 挂载点\n/dev/sda5 5039616 2757016 2026600 58% /\ntmpfs 135720 0 135720 0% /dev/shm\n/dev/sda1 99150 27098 66932 29% /boot\n/dev/sda8 481685144 1082644 456134276 1% /data\n/dev/sda6 5039616 141080 4642536 3% /home\n/dev/sda2 10079084 2660636 6906448 28% /usr\n/dev/sda3 10079084 274864 9292220 3% /var\n'
在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\n/dev/sda5 4.9G 2.7G 2.0G 58% /\ntmpfs 133M 0 133M 0% /dev/shm\n/dev/sda1 97M 27M 66M 29% /boot\n/dev/sda8 460G 1.1G 436G 1% /data\n/dev/sda6 4.9G 138M 4.5G 3% /home\n/dev/sda2 9.7G 2.6G 6.6G 28% /usr\n/dev/sda3 9.7G 269M 8.9G 3% /var\n' #没有错误信息,标准错误 >>> 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'\nTry `df --help' for more information.\n"
出错,但整个程序没有报错
加上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\n' >>>
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\n/dev/sda5 4.9G 2.7G 2.0G 58% /\ntmpfs 133M 0 133M 0% /dev/shm\n/dev/sda1 97M 27M 66M 29% /boot\n/dev/sda8 460G 1.1G 436G 1% /data\n/dev/sda6 4.9G 138M 4.5G 3% /home\n/dev/sda2 9.7G 2.6G 6.6G 28% /usr\n/dev/sda3 9.7G 269M 8.9G 3% /var')
subprocess.getoutput() 方法
接收字符串格式命令,并返回结果,只返回结果
>>> subprocess.getoutput('df -h') 'Filesystem Size Used Avail Use% Mounted on\n/dev/sda5 4.9G 2.7G 2.0G 58% /\ntmpfs 133M 0 133M 0% /dev/shm\n/dev/sda1 97M 27M 66M 29% /boot\n/dev/sda8 460G 1.1G 436G 1% /data\n/dev/sda6 4.9G 138M 4.5G 3% /home\n/dev/sda2 9.7G 2.6G 6.6G 28% /usr\n/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\n/dev/sda5 4.9G 2.7G 2.0G 58% /\ntmpfs 133M 0 133M 0% /dev/shm\n/dev/sda1 97M 27M 66M 29% /boot\n/dev/sda8 460G 1.1G 436G 1% /data\n/dev/sda6 4.9G 138M 4.5G 3% /home\n/dev/sda2 9.7G 2.6G 6.6G 28% /usr\n/dev/sda3 9.7G 269M 8.9G 3% /var\n' >>> >>> res = subprocess.check_output(['df', '-h']) >>> res b'Filesystem Size Used Avail Use% Mounted on\n/dev/sda5 4.9G 2.7G 2.0G 58% /\ntmpfs 133M 0 133M 0% /dev/shm\n/dev/sda1 97M 27M 66M 29% /boot\n/dev/sda8 460G 1.1G 436G 1% /data\n/dev/sda6 4.9G 138M 4.5G 3% /home\n/dev/sda2 9.7G 2.6G 6.6G 28% /usr\n/dev/sda3 9.7G 269M 8.9G 3% /var\n'
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()方法来检测一下命令是否执行完成就好了。