[关闭]
@bergus 2015-12-02T14:50:59.000000Z 字数 3335 阅读 1448

python执行外部程序模块pyshell

python pyshell


写python程序的时候需要用到调用外部命令的模块,看了一下,还真不少,头疼,用着不顺手。根据官网推荐,我根据官网的subprocess模块定制了一个自己的shell,同时借鉴了github上面的shellpy模块,而且我觉得go语言的go-sh确实令人喜欢,所以我觉得基于流操作将会改变我们的很多工作。

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import shlex
  4. from subprocess import Popen
  5. from subprocess import PIPE
  6. def py_ver():
  7. '''
  8. 判断python的版本
  9. '''
  10. import sys
  11. return sys.version_info[0]
  12. if py_ver() == 2:
  13. builtin_str = str
  14. bytes = str
  15. str = unicode
  16. basestring = basestring
  17. numeric_types = (int, long, float)
  18. elif py_ver() == 3:
  19. builtin_str = str
  20. str = str
  21. bytes = bytes
  22. basestring = (str, bytes)
  23. numeric_types = (int, float)
  24. else:
  25. raise ValueError(u'python 版本不正确')
  26. def parse_shell_token(t):
  27. import os
  28. # handle '~'
  29. t = os.path.expanduser(t)
  30. # handle env var
  31. t = os.path.expandvars(t)
  32. return t
  33. def pipe_to_tmp(data):
  34. '''
  35. 把管道或者内存中的数据缓存到临时文件
  36. '''
  37. if isinstance(data, (unicode, str)):
  38. data = data.encode('utf-8')
  39. import tempfile
  40. stdin_tmp = tempfile.SpooledTemporaryFile()
  41. stdin_tmp.write(data)
  42. stdin_tmp.seek(0)
  43. return stdin_tmp
  44. class Shell(object):
  45. def __init__(self, cmd_str, input_pipe=None):
  46. self.cmd_str = cmd_str
  47. self.popen = None
  48. self.input_pipe = input_pipe
  49. self.std = {'out': None, 'err': None}
  50. def __getPopen(self):
  51. if self.popen is None:
  52. self.popen = Popen(
  53. map(parse_shell_token, shlex.split(self.cmd_str, posix=False)),
  54. stdin=self.input_pipe, stdout=PIPE, stderr=PIPE)
  55. return self.popen
  56. def pipe(self, cmd_str):
  57. input_pipe = None
  58. pp = self.__getPopen()
  59. if pp.stdout.closed:
  60. # 如果命令已经执行,那么就把标准输出的结果保存到临时文件
  61. input_pipe = pipe_to_tmp(self.std['out'])
  62. else:
  63. input_pipe = pp.stdout
  64. # print input_pipe.read()
  65. # pp.stdout.close() # allow pp to receive SIGPIPE?
  66. return Shell(cmd_str, input_pipe=input_pipe)
  67. def __communicate(self):
  68. pp = self.__getPopen()
  69. if pp.returncode is None:
  70. self.std['out'], self.std['err'] = pp.communicate()
  71. def run(self):
  72. if self.std['out'] is None:
  73. self.__communicate()
  74. print self.std['out']
  75. def stdout(self):
  76. if self.std['out'] is None:
  77. self.__communicate()
  78. return self.std['out']
  79. def stderr(self):
  80. if self.std['err'] is None:
  81. self.__communicate()
  82. return self.std['err']
  83. cmd = Shell
  84. if __name__ == '__main__':
  85. # cmd('ls -l').run()
  86. # cmd('ls -l').pipe('grep Shell.py').run()
  87. # cmd('cat').pipe('> hello;cat hello').run()
  88. # cmd('ls ~').run()
  89. cmd('echo dddd').run()
  90. #下面这个是改良版本,参考了python的bash类库的实现,仅用于学习
  91. #!/usr/bin/env python
  92. # -*- coding:utf-8 -*-
  93. from subprocess import Popen
  94. from subprocess import PIPE
  95. import shlex
  96. def py_ver():
  97. '''
  98. 得到python的版本
  99. '''
  100. import sys
  101. return sys.version_info[0]
  102. _ver = py_ver()
  103. if _ver == 2:
  104. builtin_str = str
  105. bytes = str
  106. str = unicode
  107. basestring = basestring
  108. numeric_types = (int, long, float)
  109. elif _ver == 3:
  110. builtin_str = str
  111. str = str
  112. bytes = bytes
  113. basestring = (str, bytes)
  114. numeric_types = (int, float)
  115. else:
  116. raise ValueError(u'python 版本不正确')
  117. del _ver
  118. #解析字符串中的环境变量
  119. def parse_shell_token(t):
  120. import os
  121. #将~等用用户的家目录进行替换
  122. t = os.path.expanduser(t)
  123. #path中可以使用环境变量,'$PATH'...
  124. t = os.path.expandvars(t)
  125. return t
  126. class cmd(object):
  127. def __init__(self, *args, **kwargs):
  128. self.stdout = None
  129. self.cmd(*args, **kwargs)
  130. def cmd(self, cmd, env=None, stdout=PIPE):
  131. p = Popen(parse_shell_token(cmd), shell=True,
  132. stdout=stdout, stdin=PIPE, stderr=PIPE, env=env)
  133. self.stdout, self.stderr = p.communicate(input=self.stdout)
  134. self.code = p.returncode
  135. return self
  136. def __repr__(self):
  137. return self.value()
  138. def __unicode__(self):
  139. return self.value()
  140. def __str__(self):
  141. return self.value()
  142. def __nonzero__(self):
  143. return self.__bool__()
  144. def __bool__(self):
  145. return bool(self.value())
  146. def value(self):
  147. if not self.stdout:
  148. return ''
  149. return self.stdout.strip()
  150. if __name__ == '__main__':
  151. #print cmd('ls -l')
  152. print cmd("ls . | grep 'pyc'")
  153. #print cmd("konsole --hold -e 'konsole --help'")
  154. #print cmd('scrapy list')
  155. print cmd('ls $HOME')
  156. #print cmd('ls ~')
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注