python subprocess模块

python

我们经常需要通过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()方法来检测一下命令是否执行完成就好了。

 

 

以上是 python subprocess模块 的全部内容, 来源链接: utcz.com/z/389275.html

回到顶部