玖叶教程网

前端编程开发入门

在python中使用supprocess代替os.system

在python开发和面试中,我们经常需要在系统上通过命令与操作系统进行交互。在面试中常问到熟悉的库很多人第一印象提到的也是os库。

因为早期的python开发中,我们主要通过os.system(),os.popen().read()等函数来调用命令。但在python2.4+开始,官方文档中建议使用的是subprocess模块。

subprocess它允许你生成新的进程,连接到它们的 input/output/error 管道,并获取它们的返回(状态)码。

subprocess模块与标准库中的其它模块相比,提供了一个更高级的接口。用于替换如下模块: os.system() , os.spawnv() , os和popen2模块中的popen()函数,以及 commands().

1. subprocess模块中的常用函数

  1. subprocess.run() Python 3.5中新增的函数。执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。
  2. subprocess.call() 执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd)。?subprocess.check_call() Python 2.5中新增的函数。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。其功能等价于subprocess.run(..., check=True)。
  3. ?subprocess.check_output() Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。
  4. ?subprocess.getoutput(cmd) 接收字符串格式的命令,执行命令并返回执行结果,其功能类似于os.popen(cmd).read()和commands.getoutput(cmd)。
  5. ?subprocess.getstatusoutput(cmd) 执行cmd命令,返回一个元组(命令执行状态, 命令执行结果输出),其功能类似于commands.getstatusoutput()。

在python3.5以后,官方提倡通过subprocess.run()函数替代其他函数来使用?subproccess模块;?

在python 3.5以前,我们可以通过subprocess.call(),subprocess.getoutput()等上面列出的其他函数来使用subprocess模块的功能;

subprocess.run()、subprocess.call()、subprocess.check_call()和subprocess.check_output()都是通过对subprocess.Popen的封装来实现的高级函数,因此如果我们需要更复杂功能时,可以通过subprocess.Popen来完成。

subprocess.getoutput()和subprocess.getstatusoutput()函数是来自python2+的commands模块的两个遗留函数。它们隐式的调用系统shell,并且不保证其他函数所具有的安全性和异常处理的一致性。另外,它们从python3.3+开始才支持Windows平台。

subprocess函数参数列表:

  • subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, universal_newlines=False)
  • subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
  • subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
  • subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)
  • subprocess.getstatusoutput(cmd)
  • subprocess.getoutput(cmd)

参数说明:

args: 要执行的shell命令,默认应该是一个字符串序列,如['df', '-Th']或('df', '-Th'),也可以是一个字符串,如'df -Th',但是此时需要把shell参数的值置为True。

shell: 如果shell为True,那么指定的命令将通过shell执行。如果我们需要访问某些shell的特性,如管道、文件名通配符、环境变量扩展功能,这将是非常有用的。当然,python本身也提供了许多类似shell的特性的实现,如glob、fnmatch、os.walk()、os.path.expandvars()、os.expanduser()和shutil等。

check: 如果check参数的值是True,且执行命令的进程以非0状态码退出,则会抛出一个CalledProcessError的异常,且该异常对象会包含 参数、退出状态码、以及stdout和stderr(如果它们有被捕获的话)。

stdout, stderr

run()函数默认不会捕获命令执行结果的正常输出和错误输出,如果我们向获取这些内容需要传递subprocess.PIPE,然后可以通过返回的CompletedProcess类实例的stdout和stderr属性或捕获相应的内容;

call()和check_call()函数返回的是命令执行的状态码,而不是CompletedProcess类实例,所以对于它们而言,stdout和stderr不适合赋值为subprocess.PIPE;

check_output()函数默认就会返回命令执行结果,所以不用设置stdout的值,如果我们希望在结果中捕获错误信息,可以执行stderr=subprocess.STDOUT。

input: 该参数是传递给Popen.communicate(),通常该参数的值必须是一个字节序列,如果universal_newlines=True,则其值应该是一个字符串。

universal_newlines: 该参数影响的是输入与输出的数据格式,比如它的值默认为False,此时stdout和stderr的输出是字节序列;当该参数的值设置为True时,stdout和stderr的输出是字符串。

例子:

import subprocess
subprocess.run(["ipconfig","ping 192.168.1.1"]) #同时执行多条命令

subprocess.run("df -h |grep book",shell=True) #把book文件过滤出来(涉及到管道符直接把字符串传给真正在调用的shell)

#执行命令,返回命令执行状态 , 0 or 非0 和os.sys一样
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
b'total 0\ndrwxr-xr-x 12 alex staff 408 Nov 2 11:05 OldBoyCRM\n'

##把结果存在管道里,用stdout读取
res=subprocess.Popen("ifconfig|grep 192",shell=True,stdout=subprocess.PIPE)
res.stdout.read()

##stdout对屏幕的标准输出
##stdin 标准输入
##stderr 把错误单独分开
res=subprocess.Popen("ifcontttfig|grep 192",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
res.stdout.read() #因为命令错误所以读取为空
res.stderr.read() #读取错误信息

# poll()
res=subprocess.Popen("slppe 10;echo 'hello'",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print(res.poll())#输出none代表命令程序没有执行完,返回0表示命令程序执行完。
res.wait() #等待命令执行完后返回0
res.terminate() #杀死正在执行程序,读取程序信息是空

# cwd
res=subprocess.Popen("slppe 10;echo 'hello'",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,cwd="/opt")
res.stdout.read() #b'/opt \n'新启动的shell目录所在的地方

#sudo自动输入密码
echo"123456" | sudo -S apt-get install vim #自动输密码
subprocess.Popen("echo'123456' | sudo -S apt-get install vim",shell=True) #linux下调用python实现自动输入密码

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言