Python封装shell命令实例分析

本文实例讲述了Python封装shell命令的方法。分享给大家供大家参考。具体实现方法如下:

# -*- coding: utf-8 -*-
import os
import subprocess
import signal
import pwd
import sys
class MockLogger(object):
  '''模拟日志类。方便单元测试。'''
  def __init__(self):
    self.info = self.error = self.critical = self.debug
  def debug(self, msg):
    print "LOGGER:"+msg
class Shell(object):
  '''完成Shell脚本的包装。
  执行结果存放在Shell.ret_code, Shell.ret_info, Shell.err_info中
  run()为普通调用,会等待shell命令返回。
  run_background()为异步调用,会立刻返回,不等待shell命令完成
  异步调用时,可以使用get_status()查询状态,或使用wait()进入阻塞状态,
  等待shell执行完成。
  异步调用时,使用kill()强行停止脚本后,仍然需要使用wait()等待真正退出。
  TODO 未验证Shell命令含有超大结果输出时的情况。
  '''
  def __init__(self, cmd):
    self.cmd = cmd # cmd包括命令和参数
    self.ret_code = None
    self.ret_info = None
    self.err_info = None
    #使用时可替换为具体的logger
    self.logger = MockLogger()
  def run_background(self):
    '''以非阻塞方式执行shell命令(Popen的默认方式)。
    '''
    self.logger.debug("run %s"%self.cmd)
    # Popen在要执行的命令不存在时会抛出OSError异常,但shell=True后,
    # shell会处理命令不存在的错误,因此没有了OSError异常,故不用处理
    self._process = subprocess.Popen(self.cmd, shell=True,
        stdout=subprocess.PIPE, stderr=subprocess.PIPE) #非阻塞
  def run(self):
    '''以阻塞方式执行shell命令。
    '''
    self.run_background()
    self.wait()
  def run_cmd(self, cmd):
    '''直接执行某条命令。方便一个实例重复使用执行多条命令。
    '''
    self.cmd = cmd
    self.run()
  def wait(self):
    '''等待shell执行完成。
    '''
    self.logger.debug("waiting %s"%self.cmd)
    self.ret_info, self.err_info = self._process.communicate() #阻塞
    # returncode: A negative value -N indicates that the child was
    # terminated by signal N
    self.ret_code = self._process.returncode
    self.logger.debug("waiting %s done. return code is %d"%(self.cmd,
              self.ret_code))
  def get_status(self):
    '''获取脚本运行状态(RUNNING|FINISHED)
    '''
    retcode = self._process.poll()
    if retcode == None:
      status = "RUNNING"
    else:
      status = "FINISHED"
    self.logger.debug("%s status is %s"%(self.cmd, status))
    return status
  # Python2.4的subprocess还没有send_signal,terminate,kill
  # 所以这里要山寨一把,2.7可直接用self._process的kill()
  def send_signal(self, sig):
    self.logger.debug("send signal %s to %s"%(sig, self.cmd))
    os.kill(self._process.pid, sig)
  def terminate(self):
    self.send_signal(signal.SIGTERM)
  def kill(self):
    self.send_signal(signal.SIGKILL)
  def print_result(self):
    print "return code:", self.ret_code
    print "return info:", self.ret_info
    print " error info:", self.err_info
class RemoteShell(Shell):
  '''远程执行命令(ssh方式)。
  XXX 含特殊字符的命令可能导致调用失效,如双引号,美元号$
  NOTE 若cmd含有双引号,可使用RemoteShell2
  '''
  def __init__(self, cmd, ip):
    ssh = ("ssh -o PreferredAuthentications=publickey -o "
        "StrictHostKeyChecking=no -o ConnectTimeout=10")
    # 不必检查IP有效性,也不必检查信任关系,有问题shell会报错
    cmd = '%s %s "%s"'%(ssh, ip, cmd)
    Shell.__init__(self, cmd)
class RemoteShell2(RemoteShell):
  '''与RemoteShell相同,只是变换了引号。
  '''
  def __init__(self, cmd, ip):
    RemoteShell.__init__(self, cmd, ip)
    self.cmd = "%s %s '%s'"%(ssh, ip, cmd)
class SuShell(Shell):
  '''切换用户执行命令(su方式)。
  XXX 只适合使用root切换至其它用户。
    因为其它切换用户后需要输入密码,这样程序会挂住。
  XXX 含特殊字符的命令可能导致调用失效,如双引号,美元号$
  NOTE 若cmd含有双引号,可使用SuShell2
  '''
  def __init__(self, cmd, user):
    if os.getuid() != 0: # 非root用户直接报错
      raise Exception('SuShell must be called by root user!')
    cmd = 'su - %s -c "%s"'%(user, cmd)
    Shell.__init__(self, cmd)
class SuShell2(SuShell):
  '''与SuShell相同,只是变换了引号。
  '''
  def __init__(self, cmd, user):
    SuShell.__init__(self, cmd, user)
    self.cmd = "su - %s -c '%s'"%(user, cmd)
class SuShellDeprecated(Shell):
  '''切换用户执行命令(setuid方式)。
  执行的函数为run2,而不是run
  XXX 以“不干净”的方式运行:仅切换用户和组,环境变量信息不变。
  XXX 无法获取命令的ret_code, ret_info, err_info
  XXX 只适合使用root切换至其它用户。
  '''
  def __init__(self, cmd, user):
    self.user = user
    Shell.__init__(self, cmd)
  def run2(self):
    if os.getuid() != 0: # 非root用户直接报错
      raise Exception('SuShell2 must be called by root user!')
    child_pid = os.fork()
    if child_pid == 0: # 子进程干活
      uid, gid = pwd.getpwnam(self.user)[2:4]
      os.setgid(gid) # 必须先设置组
      os.setuid(uid)
      self.run()
      sys.exit(0) # 子进程退出,防止继续执行其它代码
    else: # 父进程等待子进程退出
      os.waitpid(child_pid, 0)
if __name__ == "__main__":
  '''test code'''
  # 1. test normal
  sa = Shell('who')
  sa.run()
  sa.print_result()
  # 2. test stderr
  sb = Shell('ls /export/dir_should_not_exists')
  sb.run()
  sb.print_result()
  # 3. test background
  sc = Shell('sleep 1')
  sc.run_background()
  print 'hello from parent process'
  print "return code:", sc.ret_code
  print "status:", sc.get_status()
  sc.wait()
  sc.print_result()
  # 4. test kill
  import time
  sd = Shell('sleep 2')
  sd.run_background()
  time.sleep(1)
  sd.kill()
  sd.wait() # NOTE, still need to wait
  sd.print_result()
  # 5. test multiple command and uncompleted command output
  se = Shell('pwd;sleep 1;pwd;pwd')
  se.run_background()
  time.sleep(1)
  se.kill()
  se.wait() # NOTE, still need to wait
  se.print_result()
  # 6. test wrong command
  sf = Shell('aaaaa')
  sf.run()
  sf.print_result()
  # 7. test instance reuse to run other command
  sf.cmd = 'echo aaaaa'
  sf.run()
  sf.print_result()
  sg = RemoteShell('pwd', '127.0.0.1')
  sg.run()
  sg.print_result()
  # unreachable ip
  sg2 = RemoteShell('pwd', '17.0.0.1')
  sg2.run()
  sg2.print_result()
  # invalid ip
  sg3 = RemoteShell('pwd', '1711.0.0.1')
  sg3.run()
  sg3.print_result()
  # ip without trust relation
  sg3 = RemoteShell('pwd', '10.145.132.247')
  sg3.run()
  sg3.print_result()
  sh = SuShell('pwd', 'ossuser')
  sh.run()
  sh.print_result()
  # wrong user
  si = SuShell('pwd', 'ossuser123')
  si.run()
  si.print_result()
  # user need password
  si = SuShell('pwd', 'root')
  si.run()
  si.print_result()

希望本文所述对大家的Python程序设计有所帮助。

(0)

相关推荐

  • Linux下使用python调用top命令获得CPU利用率

    本文定位:想通过python调用top命令获取cpu使用率但暂时没有思路的情况. 如果单纯为了获得cpu的利用率,通过top命令重定向可以轻松实现,命令如下: 复制代码 代码如下: top -bi > cpuHistory.log 或 复制代码 代码如下: top -bi | tee  cpuHistory.log 这个就不解释了,不懂的朋友查询下top的帮助文档.这里要实现的是通过python调用top命令,并获得cpu的利用率信息. 用过popen的朋友很快就能想到类似如下的代码(这个是我第

  • python命令行参数解析OptionParser类用法实例

    本文实例讲述了python命令行参数解析OptionParser类的用法,分享给大家供大家参考. 具体代码如下: from optparse import OptionParser parser = OptionParser(usage="usage:%prog [optinos] filepath") parser.add_option("-t", "--timeout", action = "store", type =

  • Python执行Linux系统命令的4种方法

    (1) os.system 仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息 复制代码 代码如下: system(command) -> exit_status Execute the command (a string) in a subshell. 如果再命令行下执行,结果直接打印出来 复制代码 代码如下: >>> os.system('ls') 04101419778.CHM   bash      document    media      py-django

  • Nodejs中调用系统命令、Shell脚本和Python脚本的方法和实例

    每种语言都有自己的优势,互相结合起来各取所长程序执行起来效率更高或者说哪种实现方式较简单就用哪个,nodejs是利用子进程来调用系统命令或者文件,文档见http://nodejs.org/api/child_process.html,NodeJS子进程提供了与系统交互的重要接口,其主要API有: 标准输入.标准输出及标准错误输出的接口. NodeJS 子进程提供了与系统交互的重要接口,其主要 API 有: 标准输入.标准输出及标准错误输出的接口 child.stdin 获取标准输入 child.

  • 日常整理python执行系统命令的常见方法(全)

    具体内容如下: 1 os.system 例如 ipython中运行如下命令,返回运行状态status os.system('cat /etc/passwdqc.conf') min=disabled,24,11,8,7 max=40 passphrase=3 match=4 similar=deny random=47 enforce=everyone retry=3 Out[6]: 0 2 os.popen() popen(command [, mode='r' [, bufsize]]) -

  • 让 python 命令行也可以自动补全

    许多人都知道 iPython 有很好的自动补全能力,但是就未必知道 python 也同样可以 Tab 键补全, 您可以在启动 python 后,执行下 复制代码 代码如下: import readline, rlcompleter; readline.parse_and_bind("tab: complete") 这就可以按 Tab 键补全了. python 自启动 如果您嫌每次都要键入这东西麻烦的话,可以把上边这行写到 ~/.pythonstartup.py , 再 ~/.bashr

  • python实现读取命令行参数的方法

    本文实例讲述了python读取命令行参数的方法.分享给大家供大家参考.具体分析如下: 如果想对python脚本传参数,python中对应的argc, argv(c语言的命令行参数)是什么呢? 需要模块:sys 参数个数:len(sys.argv) 脚本名:    sys.argv[0] 参数1:     sys.argv[1] 参数2:     sys.argv[2] test.py: import sys print "脚本名:", sys.argv[0] for i in rang

  • Python封装shell命令实例分析

    本文实例讲述了Python封装shell命令的方法.分享给大家供大家参考.具体实现方法如下: # -*- coding: utf-8 -*- import os import subprocess import signal import pwd import sys class MockLogger(object): '''模拟日志类.方便单元测试.''' def __init__(self): self.info = self.error = self.critical = self.deb

  • python 执行shell命令并将结果保存的实例

    方法1: 将shell执行的结果保存到字符串 def run_cmd(cmd): result_str='' process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) result_f = process.stdout error_f = process.stderr errors = error_f.read() if errors: pass result_str =

  • python SSH模块登录,远程机执行shell命令实例解析

    用python SSH模块登录,并在远程机执行shell命令 (在CentOS 7 环境试验成功, Redhat 系列应该是兼容的.) 先安装必须的模块 # yum install python-dev # yum install python-devel # pip install pycrypto # pip install paramiko # pip install ssh 这些都成功后, 编写一个Python脚本 # vim remote_run.py import ssh # 新建一

  • 使用Python生成Shell命令,批量执行程序代码解析

    本文主要研究的是Linux系统中使用Python生成Shell命令,批量执行程序的相关内容,具体如下. 近日经常遇到在Linux shell中批量执行相似命令的情况.比如执行如下命令: gifsicle --delay=100 gif/App_1_hour_*_down.gif > combine_gif/App_1_hour_down.gif gifsicle --delay=100 gif/App_1_hour_*_up.gif > combine_gif/App_1_hour_up.gi

  • Python调用shell命令常用方法(4种)

    方法一.使用os模块的system方法:os.system(cmd),其返回值是shell指令运行后返回的状态码,int类型,0表示shell指令成功执行,256表示未找到,该方法适用于shell命令不需要输出内容的场景. 举例说明: 1. 列举当前目录下的所有文件. import os val = os.system('ls -al') print val 没有找到时,sh返回的状态码是1,而适用python调用,返回的是:256 方法二.使用os.popen(),该方法以文件的形式返回she

  • Python iter()函数用法实例分析

    本文实例讲述了Python iter()函数用法.分享给大家供大家参考,具体如下: python中的迭代器用起来非常灵巧,不仅可以迭代序列,也可以迭代表现出序列行为的对象,例如字典的键.一个文件的行,等等. 迭代器就是有一个next()方法的对象,而不是通过索引来计数.当使用一个循环机制需要下一个项时,调用迭代器的next()方法,迭代完后引发一个StopIteration异常. 但是迭代器只能向后移动.不能回到开始.再次迭代只能创建另一个新的迭代对象. 反序迭代工具:reversed()将返回

  • Python callable()函数用法实例分析

    本文实例讲述了Python callable()函数用法.分享给大家供大家参考,具体如下: python中的内建函数callable( ) ,可以检查一个对象是否是可调用的 . 对于函数, 方法, lambda 函数式, 类, 以及实现了 _ _call_ _ 方法的类实例, 它都返回 True. >>> help(callable) Help on built-in function callable in module __builtin__: callable(...) calla

  • 解决python 执行shell命令无法获取返回值的问题

    问题背景:利用python获取服务器中supervisor状态信息时发现未能获取到返回值. python获取执行shell命令后返回值得几种方式: # 1.os模块 ret = os.popen("supervisorctl status") ret_data = ret.read() # 2.subprocess模块 ret = subprocess.Popen('supervisorctl status',shell=True,stdout=subprocess.PIPE) out

  • Python Selenium异常处理的实例分析

    1.说明 在使用selenium时,不可避免的会遇到一些异常情况,比如超时.没有找到节点的错误等等.一旦出现这样的错误,程序就不能再运行了.这里我们可以使用tryexcept语句来捕捉异常. 2.实例 from selenium import webdriver from selenium.common.exceptions import TimeoutException, NoSuchElementException browser = webdriver.Chrome() try: brow

  • 利用python调用摄像头的实例分析

    这篇文章主要介绍了python调用摄像头的示例代码,帮助大家更好的理解和使用python,感兴趣的朋友可以了解下 一.打开摄像头 import cv2 import numpy as np def video_demo(): capture = cv2.VideoCapture(0)#0为电脑内置摄像头 while(True): ret, frame = capture.read()#摄像头读取,ret为是否成功打开摄像头,true,false. frame为视频的每一帧图像 frame = c

随机推荐