前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >正确的使用python调用shell的姿势

正确的使用python调用shell的姿势

作者头像
我是攻城师
发布2020-04-22 12:09:07
7.5K0
发布2020-04-22 12:09:07
举报
文章被收录于专栏:我是攻城师

python是一门简洁灵活的语言,也是一门胶水语言,能与很多其他的编程语言进行交互,虽然性能差一点,但易用,入门和上手都比较简单,所以一直以来都被使用广泛。

python天生的优势,用它来开发一些devops的自动化作业是非常方便的,当然在linux上,一般我们用shell就能写一些简单的自动化脚本,但如果自动化作业复杂的话,使用shell脚本就很难搞定了,一方面shell脚本量变大就会比较难以工程化,维护和阅读,另外一个重要的原因是shell不具备正经编程语言所具备的丰富的一些类库,比如说map类型必须得bash版本4.x以上才有,或者有序list什么的也没有,这个时候我们就可以用python来搞定了,python能与shell直接交互,所以两者结合,相互取长补短,就非常适合开发各种自动化作业了。

下面我们看如何使用python与shell交互:

方式一:

使用os.system方法

代码语言:javascript
复制
import osos.system("ls")

保存到一个python文件xxx.py里面执行 python xxx.py,或者直接在linux终端上执行

代码语言:javascript
复制
python -c "import os; myCmd = 'ls '; os.system(myCmd)"

这种方式是最原始的方式,能直接调用shell命令,但是没法获取输出结果,所以仅仅适合一些简单的场景

方式二:

使用os.popen方法

代码语言:javascript
复制
import osstream = os.popen('echo 123')output = stream.read()print output

输出123

我们可以看到popen方法可以获取命令执行后到输入结果,但这还是有缺陷的,我们知道在linux里面,有标准的0,1,2来代表标准输入,输出和错误,现在只有stdout没有其他的两个变量还是有限制的,如果仔细看python的方法,会发现popen还有popen2,popen3,popen4同名方法,没错就是后面的版本里面完善了linux的标准输入,输出,错误等信息。

具体点:popen 支持 stdout popen2 支持stdin, stdout popen3 支持stdin, stdout, stderr popen4 支持stdin, stdout and stderr

方式三:看到上面这些这么繁琐的调用,后面就又有了最强大的subprocess模块,subprocess模块的出现是用来替代OS模块中的system()和popen()方法的,官方推荐的是只用subprocess模块来执行系统命令,subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。

Popen 是 subprocess的核心,子进程的创建和管理都靠它处理。

代码语言:javascript
复制
class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0,restore_signals=True, start_new_session=False, pass_fds=(),*, encoding=None, errors=None)

参数介绍如下:args:shell命令,可以是字符串或者序列类型(如:list,元组) bufsize:缓冲区大小。当创建标准流的管道对象时使用,默认-1。0:不使用缓冲区 1:表示行缓冲,仅当universalnewlines=True时可用,也就是文本模式 正数:表示缓冲区大小 负数:表示使用系统默认的缓冲区大小。stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄 preexecfn:只在 Unix 平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用 shell:如果该参数为 True,将通过操作系统的 shell 执行指定的命令。cwd:用于设置子进程的当前目录。env:用于指定子进程的环境变量。如果 env = None,子进程的环境变量将从父进程中继承。

一个简单的例子:

代码语言:javascript
复制
import subprocess
p = subprocess.Popen('ls -lh', shell=True)p.wait()
print p.returncode

几个主要方法,介绍:

poll(): 检查进程是否终止,如果终止返回 returncode,否则返回 None。wait(timeout): 等待子进程终止。communicate(input,timeout): 和子进程交互,发送和读取数据。send_signal(singnal): 发送信号到子进程 。terminate(): 停止子进程,也就是发送SIGTERM信号到子进程。kill(): 杀死子进程。发送 SIGKILL 信号到子进程。

这里我已经封装好了2个通用方法,一个是执行命令能够实时获取终端输出的信息,一个是可以执行命令结束后得到结果。

可以实时获取输出的:

代码语言:javascript
复制
import subprocessimport shlexdef real_run_command(command):    process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)    while True:        output = process.stdout.readline()        if output == '' and process.poll() is not None:            break        if output:            print output.strip()    rc = process.poll()    return rc

为了能够模拟效果,我写了一个简单的shell脚本:test.sh

代码语言:javascript
复制
for i in `seq 1 4`dosleep 2echo ${i}done

这个脚本每输出一个数字都会sleep 2秒,用ptyhon调用这个脚本,能够实时在终端上看到和shell一样的效果:

代码语言:javascript
复制
rc = real_run_command("sh test.sh")print 'retrurn code=%s'% rc

非实时获取输出的,这个脚本适合大部分场景:

代码语言:javascript
复制
def normal_run_command(cmd):    try:        child = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)        stdout, stderr = child.communicate()        return_code = child.returncode        if stdout:            print stdout        if stderr:            print stderr        if return_code != 0:            print "execute error, return_code=%s " % return_code            sys.exit(1)    except Exception as e:        print "execute cmd=%s occur error %s" % (cmd, e)        sys.exit(1)    return stdout, stderr, return_code

ok,同样的调用脚本,这个函数会等整个shell执行结束后,输出结果:

代码语言:javascript
复制
out, err, code= normal_run_command("sh xs.sh")print out

至此,我们已经介绍完了如何使用python和shell交互的方式,通过这种方式我们可以很轻松开发一个自动化作业,比如系统参数初始化,使用yum安装各种软件,各种业务项目的部署,启动,停止等等等等,有很多场景都可以发挥。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 我是攻城师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档