您的位置:首页 > 运维架构 > Linux

python模块之 - subprocess执行unix/linux命令

2017-08-19 17:48 239 查看
subprocess模块提供了一种一致的方法来创建和处理附加进程,与标准库中的其它模块相比,提供了一个更高级的接口,subprocess模块用来生成子进程,并可以通过管道连接它们的
输入/输出/错误,以及获得它们的返回值.它用来代替多个旧模块和函数:
os.system
os.spawn*
os.popen*
popen2.*
commands.*

1.subprocess.call( commands ) 方法 :

subprocess的call方法可以用于执行一个外部命令,但该方法不能返回执行的结果,只能返回执行的状态码:成功(0)或错误(非0)
call()方法中的commands可以是一个列表,也可以是一个字符串,作为字符串时需要用原生的shell=True来执行:

示例:

>>> import subprocess
>>> subprocess.call(["ls","-lh"])
total 8.0K
-rw-r--r--. 1 root root 941 Oct 22  2013 socket_2.py
-rw-r--r--. 1 root root 401 Oct 22  2013 socket_client.py
0
>>> subprocess.call("ls -lh",shell=True)
total 8.0K
-rw-r--r--. 1 root root 941 Oct 22  2013 socket_2.py
-rw-r--r--. 1 root root 401 Oct 22  2013 socket_client.py
0
>>>
如上实例所示,虽然我们能看到执行的结果和返回的一个状态码0,但保存为变量后实际获取的值只是状态码

>>> cmd_result = subprocess.call("ls -lh",shell=True)
total 8.0K
-rw-r--r--. 1 root root 941 Oct 22  2013 socket_2.py
-rw-r--r--. 1 root root 401 Oct 22  2013 socket_client.py
>>> print(cmd_result)
0
>>>


2.subprocess.check_call() 方法:

我们说过call执行返回一个状态码,我们可以通过check_call()函数来检测命令的执行结果,如果不成功将返回 subprocess.CalledProcessError 异常
#如果命令执行正确则返回结果,和subprocess.call效果一样.

示例:

>>> try:
...   subprocess.check_call("ls -lh",shell=True)
... except subprocess.CalledProcessError as err:
...   print("Commands error")
...
total 8.0K
-rw-r--r--. 1 root root 941 Oct 22  2013 socket_2.py
-rw-r--r--. 1 root root 401 Oct 22  2013 socket_client.py
0
>>>
#如果命令执行错误,则抛出异常.
>>> try:
...   subprocess.check_call("ls -jj",shell=True)
... except subprocess.CalledProcessError as err:
...   print("Commands error")
...
ls: invalid option -- 'j'
Try `ls --help' for more information.
Commands error
>>>


subprocess.call 和subprocess.check_call的区别:

subprocess.call:执行命令,返回结果
check_all :执行命令,如果执行状态码是0,则返回0,否则抛出异常.

subprocess.call如果命令执行错误不会抛出异常(经测试在linux系统上执行错误命令也会有异常错误,在pycharm上面则不抛出异常),而subprocess.check_call如果命令执行错误则抛出异常,如果命令执行正确则两者效果一样.

3.subprocess.Popen()方法:

函数call(), check_call() 和 check_output() 都是Popen类的包装器。直接使用Popen会对如何运行命令以及如何处理其输入输出有更多控制。如通过为stdin, stdout和stderr传递不同的参数。

1.与进程的单向通信

通过Popen()方法调用命令后执行的结果,可以设置stdout值为PIPE,再调用communicate()获取结果 返回结果为tuple. 在python3中结果为byte类型,要得到str类型需要decode转换一下输出结果(读)

# 直接执行命令输出到屏幕

>>> subprocess.Popen("ls -lh",shell=True)
<subprocess.Popen object at 0x7f8ad576c450>
>>> total 8.0K
-rw-r--r--. 1 root root 941 Oct 22  2013 socket_2.py
-rw-r--r--. 1 root root 401 Oct 22  2013 socket_client.py

>>>

# 不输出到屏幕,输出到变量
#读取字符串
>>> cmd_result=subprocess.Popen(["echo","welcome to china"],stdout=subprocess.PIPE)
>>> print(cmd_result)
<subprocess.Popen object at 0x7f8ad576c9d0>
>>> stdout_var=cmd_result.communicate()
>>> stdout_var
('welcome to china\n', None)
>>> print((stdout_var[0]).decode('utf-8'))
welcome to china

>>>

#读取命令输出结果
>>> cmd_result=subprocess.Popen(["ls","-lh"],stdout=subprocess.PIPE)
>>> print(cmd_result)
<subprocess.Popen object at 0x7f8ad576c990>
>>> stdout_var=cmd_result.communicate()
>>> print((stdout_var[0]).decode("utf-8"))
total 8.0K
-rw-r--r--. 1 root root 941 Oct 22  2013 socket_2.py
-rw-r--r--. 1 root root 401 Oct 22  2013 socket_client.py

>>>

#将结果输出到文件

>>> file_handle = open("/tmp/t.logs","w+")
>>> subprocess.Popen("ls -lh",shell=True,stdout=file_handle)
<subprocess.Popen object at 0x7f8ad576c990>
>>>

#在指定路径创建目录

>>> import subprocess
>>> obj = subprocess.Popen("mkdir t3",shell=True,cwd="/tmp",)
>>> obj = subprocess.Popen("mkdir t4",shell=True,cwd="/tmp")
>>>


2 与进程的双向通信:  

>>> cmd_result=subprocess.Popen("cat",shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE)
>>> msg="Hello World".encode("utf-8")
# 写入到输入管道
>>> cmd_result.stdin.write(msg)
>>> stdout_var=cmd_result.communicate()
>>> stdout_var
('Hello World', None)
>>> (stdout_var[0]).decode("utf-8")
u'Hello World'
>>> (stdout_var[0]).decode()
u'Hello World'
>>>
>>> stdout_var[0]
'Hello World'
>>>

#打开一个python终端,执行python print命令.
>>> cmd_result=subprocess.Popen(["python"],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> cmd_result.stdin.write('print("Good luck!")'.encode("utf-8"))
>>> stdin_var,err_var=cmd_result.communicate()
>>> print(err_var)

>>> print(stdin_var)
Good luck!
>>> stdin_var
'Good luck!\n'
>>>


Popen其它方法:

poll() 检查是否结束,设置返回值
wait()等待结束,设置返回值
communicate()参数是标准输入,返回标准输出和标准出错
send_signal()发送信号 (主要在unix下有用)
terminate()终止进程,unix对应的SIGTERM信号,windows下调用api函数TerminateProcess()
kill()杀死进程(unix对应SIGKILL信号),windows下同上
stdin
stdout
stderr
参数中指定PIPE时,有用
pid进程id
returncode进程返回值
脚本实例:

#!/usr/bin/env python
#coding:utf-8

import os
import time
import subprocess

packge_dir = "/root/.jenkins/workspace/pre-php-p/"
remote_ip = "59.110.164.99"
remote_port = "'-e ssh -p 6168'"
backup_dir= '/data/backup/' + time.strftime('%Y%m%d')
source_dir="shop-H5"
source_URL="/data/web/xd"

def backup_php():
tagz = backup_dir + os.sep + source_dir + "_" + time.strftime('%Y%m%d%H') + '.tgz'
print "tagz=",tagz
backup_tgz = "tar -zcvf %s %s" %(tagz,source_dir)

if not os.path.exists(backup_dir):
os.mkdir(backup_dir)
print("Sucessfully created directory",backup_dir)

print("开始备份代码中...")
os.chdir(source_URL)
#os.system(backup_tgz)
#subprocess.call(backup_tgz,shell=True)

if subprocess.call(backup_tgz,shell=True) == 0:
print  "Successful backup to ", tagz
else:
print "Backup FAILED!!"

time.sleep(3)
def rsync_php():

print("开始代码同步中...")

remote_ssh = remote_ip + ":" + packge_dir

time.sleep(3)

rsyn="/usr/bin/sudo rsync -avH --progress --exclude=.git %s %s %s" %(remote_port,remote_ssh,source_dir)
#print rsyn

if subprocess.call(rsyn,shell=True) == 0:
print("同步代码成功...")

else:
print("同步代码失败,check...")

#os.chown(source_dir,504,504)
mattr="chown -R phpci:phpci %s" %(source_dir)
subprocess.call(mattr,shell=True)

if __name__ == "__main__":
backup_php()
rsync_php()


PHP代码备份及目录过滤

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: