参考
python中os.system、os.popen、subprocess.popen的区别
Python执行系统命令的方法 os.system(),os.popen(),commands
Python subprocess模块功能与常见用法实例详解
一、概要
由于之前接触了一个项目,做发布系统,其中需要去git拉代码并且checkout到对应的Tag或者是分支,这就要求需要使用Python来执行系统命令,于是开始接触到了Python中的执行命令
如果想要在Python中调用cmd指令,有四种方法:
- os.system
- os.popen
- commands(Python3已废除)
- subprocess模块
二、os.system
用来执行cmd指令,在cmd输出的内容会直接在控制台输出,返回结果为0表示执行成功
system()函数在执行过程中进行了以下三步操作:
- fork一个子进程
- 在子进程中调用exec函数去执行命令
- 在父进程调用wait(阻塞)去等待子进程结束
对于fork失败,system函数会返回-1
注意: 由于使用该函数经常会莫名其妙地出现错误,但是直接执行命令并没有问题,所以一般建议不要使用。
注意:os.system是简单粗暴的执行cmd指令,如果想获取在cmd输出的内容,是没办法获到的
注意:在Unix,Windows都有效
三、os.popen
同样是用来执行cmd指令,如果想获取控制台输出的内容,那就用os.popen的方法了,popen返回的是一个file对象,跟open打开文件一样操作了,r是以读的方式打开
popen() 创建一个管道,通过fork一个子进程,然后该子进程执行命令。返回值在标准IO流中,该管道用于父子进程间通信。父进程要么从管道读信息,要么向管道写信息,至于是读还是写取决于父进程调用popen时传递的参数(w或r)
比如:
#!/usr/bin/python
import os
p=os.popen('ssh 10.3.16.121 ls')
x=p.read()
print x
p.close()
注意:能获取到命令的执行内容,可以打印出来,但是获取不到命令是否执行成功,只是单纯输出了命令的执行结果而已
注意:os.popen() 方法用于从一个命令打开一个管道。在Unix,Windows中有效
四、subprocess模块
subprocess模块是在2.4版本中新增的,官方文档中描述为可以用来替换以下函数:os.system、os.spawn、os.popen、popen2
参数既可以是string字符串,也可以是list列表
比如:
subprocess.Popen([“cat”,”test.txt”])
subprocess.Popen(“cat test.txt”, shell=True)
对于参数是字符串,需要指定shell=True,官方建议使用list列表
参数有:
比如:subprocess.call代替os.system
执行命令,返回命令的结果和执行状态,0或者非0
import subprocess
retcode = subprocess.call('ls -l', shell=True)
print(retcode)
比如:subprocess.getstatusoutput()
接受字符串形式的命令,返回 一个元组形式的结果,第一个元素是命令执行状态,第二个为执行结果
比如:
#执行正确
>>> subprocess.getstatusoutput('pwd')
(0, '/root')
#执行错误
>>> subprocess.getstatusoutput('pd')
(127, '/bin/sh: pd: command not found')
比如:subprocess.getoutput()
接受字符串形式的命令,返回执行结果
#执行正确
>>> res = subprocess.getoutput('pwd')
>>> res
'/d/software/laragon/www/test/AutoRelease'
#执行错误
>>> res = subprocess.getoutput('ip addr')
>>> res
"'ip' 不是内部或外部命令,也不是可运行的程序\n或批处理文件。"
以及还有check_output()、check_call()、run()等
注意:官方建议使用run函数,run函数是在Python 3.5增加的(https://docs.python.org/zh-cn/3.7/library/subprocess.html#module-subprocess)
>>> import subprocess
# python 解析则传入命令的每个参数的列表
>>> subprocess.run(["df","-h"])
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/VolGroup-LogVol00
289G 70G 204G 26% /
tmpfs 64G 0 64G 0% /dev/shm
/dev/sda1 283M 27M 241M 11% /boot
CompletedProcess(args=['df', '-h'], returncode=0)
# 需要交给Linux shell自己解析,则:传入命令字符串,shell=True
>>> subprocess.run("df -h|grep /dev/sda1",shell=True)
/dev/sda1 283M 27M 241M 11% /boot
CompletedProcess(args='df -h|grep /dev/sda1', returncode=0)
以上subprocess使用的方法,都是对subprocess.Popen的封装
五、代码
注意:以下代码在Windows执行,会有一些问题,最好是在Linux下运行
os.system
# -*- coding:utf-8 -*-
import os
def run_cmd(string):
print("命令为:" + cmd)
return os.system(string)
path = 'D:/software/laragon/test/'
cmd = "cd %s && rm -rf ./*" % path
res1 = run_cmd(cmd)
if res1 != 0:
print("命令出错了")
else:
print("命令成功了")
git_url = 'http://xxx/AutoRelease.git'
cmd = "cd %s && git clone %s" % (path, git_url)
res2 = run_cmd(cmd)
if res2 != 0:
print("命令出错了")
else:
print("命令成功了")
tag = 'v20190824'
cmd = "cd %s/AutoRelease && git checkout %s" % (path, tag)
res3 = run_cmd(cmd)
if res3 != 0:
print("命令出错了")
else:
print("命令成功了")
cmd = "ls -al"
res4 = run_cmd(cmd)
if res4 != 0:
print("命令出错了")
else:
print("命令成功了")
# Windows下报错,Linux下不报错
cmd = "ip addr"
res5 = run_cmd(cmd)
if res5 != 0:
print("命令出错了")
else:
print("命令成功了")
# Windows不报错,Linux下报错
cmd = "ipconfig"
res6 = run_cmd(cmd)
if res6 != 0:
print("命令出错了")
else:
print("命令成功了")
os.popen
同样是实现上面的内容,但是结果却不同:
# -*- coding:utf-8 -*-
import os
def run_cmd(string):
print("命令为:" + cmd)
output = os.popen(string)
ret = output.read()
output.close()
return ret
path = 'D:/software/laragon/test/'
cmd = "cd %s && rm -rf ./*" % path
res1 = run_cmd(cmd)
print('命令的结果为:' + res1 + "\r\n")
git_url = 'http://xxx/AutoRelease.git'
cmd = "cd %s && git clone %s" % (path, git_url)
res2 = run_cmd(cmd)
print('命令的结果为:' + res2 + "\r\n")
tag = 'v20190824'
cmd = "cd %s/AutoRelease && git checkout %s" % (path, tag)
res3 = run_cmd(cmd)
print('命令的结果为:' + res3 + "\r\n")
cmd = "ls -al"
res4 = run_cmd(cmd)
print('命令的结果为:' + res4 + "\r\n")
cmd = "ip addr"
res5 = run_cmd(cmd)
print('命令的结果为:' + res5 + "\r\n")
# Windows不报错,Linux下报错
cmd = "ipconfig"
res6 = run_cmd(cmd)
print('命令的结果为:' + res6 + "\r\n")
这个Python运行后,只有第四条和第六条命令能打印出来结果,也就是ls -al和ipconfig能打印出来,其他的命令只能在控制台看到输出结果,却打印不出来,并且也不知道执行的状态是否成功
suprocess
# -*- coding:utf-8 -*-
import subprocess
def run_cmd(string):
print("命令为:" + cmd)
(code, res) = subprocess.getstatusoutput(string)
return code, res
path = 'D:/software/laragon/test/'
cmd = "cd %s && rm -rf ./*" % path
(code, res) = run_cmd(cmd)
if code != 0:
print("命令出错了")
else:
print("命令成功了")
print('命令的结果为:' + res + "\r\n")
git_url = 'http://xxx/AutoRelease.git'
cmd = "cd %s && git clone %s" % (path, git_url)
(code, res) = run_cmd(cmd)
if code != 0:
print("命令出错了")
else:
print("命令成功了")
print('命令的结果为:' + res + "\r\n")
tag = 'v20190824'
cmd = "cd %s/AutoRelease && git checkout %s" % (path, tag)
(code, res) = run_cmd(cmd)
if code != 0:
print("命令出错了")
else:
print("命令成功了")
print('命令的结果为:' + res + "\r\n")
cmd = "ls -al"
(code, res) = run_cmd(cmd)
if code != 0:
print("命令出错了")
else:
print("命令成功了")
print('命令的结果为:' + res + "\r\n")
cmd = "ip addr"
(code, res) = run_cmd(cmd)
if code != 0:
print("命令出错了")
else:
print("命令成功了")
print('命令的结果为:' + res + "\r\n")
# Windows不报错,Linux下报错
cmd = "ipconfig"
(code, res) = run_cmd(cmd)
if code != 0:
print("命令出错了")
else:
print("命令成功了")
print('命令的结果为:' + res + "\r\n")