为了账号安全,请及时绑定邮箱和手机立即绑定

Python 实现 Shell 脚本功能

标签:
Python

最近生产环境上发现有服务器进程出现任务堆积的情况,由于一时无法定位出原因,故对堆积的任务数量进行监控。进程日志中已有任务数量的输出,故只需要编写一个脚本读取日志中的任务数量,发现任务数量超过某个阈值就发送告警短信即可。
本想使用 Shell 脚本来实现,没想到 Shell 的语法实在不好掌握,赋值语法,数值比较语法,字符串与数字的转换,等等,这些语法的问题经过了多次 google 和百度后,还是没能解决:(。一气之下,决定还是用回了自己熟悉的 Python 来实现。

Python 中执行 Shell 命令有多种方法,stackoverflow 上有对这些方法进行比较的讨论,Calling an external command in Python 指出使用subprocess模块来实现更优。因此,本文说明如何使用subprocess模块来实现 Shell 脚本的功能。
subprocess模块提供多种方法来实现执行 Linux 的命令,例如subprocess.call()方法,subprocess.check_call()方法,等。这些方法都是对Popen类的封装,故本文着重讲述Popen类的使用。

执行 Shell 命令

可以通过向Popen()传递需要执行的命令来创建一个Popen对象,这样,便会创建一个子进程来执行命令。例如:

child = subprocess.Popen(["ping","-c","5","leehao.me"])

上面的代码会创建一个子进程来执行ping -c 5 leehao.me命令,这个命令采用列表的形式传递给Popen()方法。如果我们想直接采用ping -c 5 leehao.me字符串形式,可以添加shell=True来实现:

child = subprocess.Popen("ping -c 5 leehao.me", shell=True)

官方文档指出由于安全原因故不建议使用shell=True,详细说明可以参考官方文档的描述。

等待子进程执行

子进程执行命令后,主进程并不会等待子进程执行。为了让主进程等待子进程执行结束,需要显示调用Popen.wait()方法。例如:

child = subprocess.Popen(["ping","-c","5","leehao.me"])
child.wait()print 'parent finish'

这样,主进程会等待子进程执行ping命令完毕后,才会打印出parent finish的输出。

获取执行结果

为了获取Popen()子进程的输出,可以使用Popen.communicate()方法,例如:

def subprocess_cmd(command):
    process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True)
    proc_stdout = process.communicate()[0].strip()    print proc_stdout

subprocess_cmd('echo leehao.me; echo www.leehao.me')

输出:

leehao.me
 www.leehao.me

process.communicate()方法可以实现主进程与子进程的通信。主进程可以通过它向子进程发送数据,也可以读取子进程的输出的数据。上面的例子中,我们在创建Popen对象时指定stdout=subprocess.PIPE,这样主进程便可以读取子进程的输出。
communicate()方法返回一个元组:(stdoutdata, stderrdata)process.communicate()[0]即获取子进程的标准输出。
需要指出的是,调用communicate()方法后,主进程也会等待子进程执行完毕。
上面的例子中,子进程向标准输出打印两个字符串,主进程接收到了这些输出,并打印出来。

有了上面的基础,实现我们的监控脚本就易如反掌了,下面是我们的脚本代码。为了免受骚扰,将手机号码替换了:)

附:监控脚本

from datetime import datetimeimport subprocessdef safe_int(s):
    try:
        n = int(s)    except Exception, ex:
        n = 0
    return ndef run():
    print 'begin to monitor task num, time: %s' % datetime.now()
    child = subprocess.Popen('grep "socket进入队列" /home/lihao/logs/ksb.txt | tail -n 1 | cut -d ":" -f 3',
                             shell=True, stdout=subprocess.PIPE)
    out = child.communicate()[0]
    out = out.strip()
    print(out)
    num = safe_int(out)    if num > 5:        print 'task num is over limit, num: %s, time: %s' % (num, datetime.now())
        msg = '%s, 193 task num is over limit, task num: %s' % (datetime.now(), num)
        cmd = ['/home/soft/SendMsg/SendMsg', '1', '13800138000', msg]        print cmd
        child = subprocess.Popen(cmd, cwd="/home/soft/SendMsg")
        child.wait()    else:        print 'task num is ok, num: %s, time: %s' % (num, datetime.now())if __name__ == '__main__':
    run()

参考资料

  1. https://docs.python.org/2/library/subprocess.html

  2. http://www.cnblogs.com/vamei/archive/2012/09/23/2698014.html

  3. https://stackoverflow.com/questions/17742789/running-multiple-bash-commands-with-subprocess

  4. http://blog.51cto.com/zhou123/1312791

  5. https://stackoverflow.com/questions/89228/calling-an-external-command-in-python

原文出处

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消