python中的subprocess.Popen()执⾏shell命令subprocess介绍
需要⽤到Python来执⾏shell脚本, 因此需要查看下subprocess模块⽂档。
根据官⽹⽂档描述:subprocess模块⽤于创建⼦进程,这个模块⽤于替换旧版本中的⼀些模块,如:os.system,
os.spawn*, os.popen*, os.popen*, popen2.*, commands.*, subprocess允许你能创建很多⼦进程,创建的时候能能指定⼦进程和⼦进程的输⼊、输出、错误输出管道,执⾏后能获取输出结果和执⾏状态。
subprocess模块的常⽤⽅法⽤法介绍
subprocess.run() --> python3.5中新增的函数,执⾏指定的命令,等待命令执⾏完成后返回⼀个包含执⾏结果的 CompletedProcess类的实例。
subprocess.call(): --> 执⾏指定的命令,返回命令执⾏状态,功能类似⽻os.system(cmd)
subprocess.check_call(): --> python2.5中新增的函数, 执⾏指定的命令, 如果执⾏成功则返回状态码,否则抛出异常。
【Tips】: 在python3.5之后的版本中,官⽅⽂档中提倡通过subprocess.run()函数替代其他函数来使⽤subprocess模块的功能。在python3.5之前的版本中,我们可以通过subprocess.call()来使⽤subprocess模块的功能。subprocess.run(), subprocess.call(),
subprocess.check_call()都是通过对subprocess.Popen的封装来实现的⾼级函数。
###
三. 这⼏个函数的定义以及参数
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)
shell脚本返回执行结果参数说明:
args: 要执⾏的shell命令,默认应该是⼀个字符串序列, 如['ls', '-l'], 也可以是⼀个字符串如: 'ls -l', 但是此时需要把shell参数的值置为True。【Tips】--> shell=True参数会让subprocess.call接受字符串类型的变量作为命令, 并调⽤shell去执⾏这个字符串, 当shell=False时,subprocess.call只接受数组变量作为命令, 并将数组的第⼀个元素作为命令, 剩下的全部作为该命令的参数。官⽅不推荐使⽤shell=True。
p = subprocess.run(["pwd"])
# p1 = subprocess.run(["cd"])
# p2 = subprocess.run(["ls", "-l"])
print(p)
###
###
subprocess.Popen
subprocess的⽬的就是启动⼀个新的进程并且与之通信。
subprocess模块中只定义了⼀个类: Popen。可以使⽤Popen来创建进程,并与进程进⾏复杂的交互。它的构造函数如下:
class subprocess.Popen( args,
bufsize=0,
executable=None,
stdin=None,
stdout=None,
stderr=None,
preexec_fn=None,
close_fds=False,
shell=False,
cwd=None,
env=None,
universal_newlines=False,
startupinfo=None,
creationflags=0)
###
参数args
参数args可以是字符串或者序列类型(如:list,元组),⽤于指定进程的可执⾏⽂件及其参数。如果是序列类型,第⼀个元素通常是可执⾏⽂件的路径。我们也可以显式的使⽤executeable参数来指定可执⾏⽂件的路径。
subprocess.Popen(["cat",""])
subprocess.Popen("")
这两个之中,后者将不会⼯作。因为如果是⼀个字符串的话,必须是程序的路径才可以。(考虑unix的ap
i函数exec,接受的是字符串
列表)
但是下⾯的可以⼯作
subprocess.Popen("", shell=True)
这是因为它相当于
subprocess.Popen(["/bin/sh", "-c", ""])
在*nix下,当shell=False(默认)时,Popen使⽤os.execvp()来执⾏⼦程序。args⼀般要是⼀个【列表】。如果args是个字符串的
话,会被当做是可执⾏⽂件的路径,这样就不能传⼊任何参数了。
注意:
shlex.split()可以被⽤于序列化复杂的命令参数,⽐如:
>>> shlex.split('ls ps top grep pkill')
['ls', 'ps', 'top', 'grep', 'pkill']
>>>import shlex, subprocess
>>>command_line = raw_input()
/bin/cat - -output "" -cmd "echo '$MONEY'"
>>>args = shlex.split(command_line)
>>> print args
['/bin/cat', '-input', '', '-output', '', '-cmd', "echo '$MONEY'"]
>>>p=subprocess.Popen(args)
###
可以看到,空格分隔的选项(如-input)和参数(如)会被分割为列表⾥独⽴的项,但引号⾥的或者转义过的空格不在此列
。这也有点像⼤多数shell的⾏为。
在*nix下,当shell=True时,如果arg是个字符串,就使⽤shell来解释执⾏这个字符串。如果args是个列表,则第⼀项被视为命令,
其余的都视为是给shell本⾝的参数。也就是说,等效于:
subprocess.Popen(['/bin/sh', '-c', args[0], args[1], ...])
####
参数bufsize
参数bufsize⼀般0 ⽆缓冲,1 ⾏缓冲,其他正值缓冲区⼤⼩,负值采⽤默认系统缓冲(⼀般是全缓冲)
###
参数executable
executable⼀般不⽤,args字符串或列表第⼀项表⽰程序名
###
参数stdin, stdout, stderr
参数stdin, stdout, stderr分别表⽰程序的标准输⼊、输出、错误句柄。他们可以是PIPE,⽂件描述符或⽂件对象,也可以设置为None,表⽰从⽗进程继承。
subprocess.PIPE
  在创建Popen对象时,subprocess.PIPE可以初始化stdin, stdout或stderr参数。表⽰与⼦进程通信的标准流。
subprocess.STDOUT
  创建Popen对象时,⽤于初始化stderr参数,表⽰将错误通过标准输出流输出。
###
参数shell
如果参数shell设为true,程序将通过shell来执⾏。
####
参数env
参数env是字典类型,⽤于指定⼦进程的环境变量。如果env = None,⼦进程的环境变量将从⽗进程中继承。
###
Popen的⽅法:
Popen.poll()
  ⽤于检查⼦进程是否已经结束。设置并返回returncode属性。
Popen.wait()
  等待⼦进程结束。设置并返回returncode属性。
Popenmunicate(input=None)
  与⼦进程进⾏交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到⼦进程的参数。Communicate()返回⼀个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。
Popen.send_signal(signal)
  向⼦进程发送信号。
  停⽌(stop)⼦进程。在windows平台下,该⽅法将调⽤Windows API TerminateProcess()来结束⼦进程。
Popen.kill()
  杀死⼦进程。
Popen.pid
  获取⼦进程的进程ID。
  获取进程的返回值。如果进程还没有结束,返回None。
###
进程通信:
如果想得到进程的输出,管道是个很⽅便的⽅法:
p=subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdoutput,erroutput) = pmunicate()
###
import subprocess
p = subprocess.Popen("ls", shell=True, stdout=subprocess.PIPE)
(stdoutput, erroutput) = pmunicate()
print(stdoutput)
print(erroutput)
####
pmunicate会⼀直等到进程退出,并将标准输出和标准错误输出返回,这样就可以得到⼦进程的输出了。
上⾯的例⼦通过communicate给stdin发送数据,然后使⽤⼀个tuple接收命令的执⾏结果。
上⾯,标准输出和标准错误输出是分开的,也可以合并起来,只需要将stderr参数设置为subprocess.STDOUT就可以了,这样⼦:p=subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
(stdoutput,erroutput) = pmunicate()
如果你想⼀⾏⾏处理⼦进程的输出,也没有问题:
p=subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
buff = adline()
if buff == ''and p.poll() != None:
break
死锁
但是如果你使⽤了管道,⽽⼜不去处理管道的输出,那么⼩⼼点,如果⼦进程输出数据过多,死锁就会发⽣了,⽐如下⾯的⽤法:p=subprocess.Popen("longprint", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.wait()
longprint是⼀个假想的有⼤量输出的进程,当输出达到4096时,死锁就发⽣了。当然,如果我们⽤adline或者pmunicate去清理输出,那么⽆论输出多少,死锁都是不会发⽣的。或者我们不使⽤管道,⽐如不做重定向,或者重定向到⽂件,也都是可以避免死锁的。subprocess还可以连接起来多个命令来执⾏。
在shell中我们知道,想要连接多个命令可以使⽤管道。
在subprocess中,可以使⽤上⼀个命令执⾏的输出结果作为下⼀次执⾏的输⼊。例⼦如下:
####
>

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。

发表评论