python執行外部程序模塊pyshell


  寫python程序的時候需要用到調用外部命令的模塊,看了一下,還真不少,頭疼,用着不順手。根據官網推薦,我根據官網的subprocess模塊定制了一個自己的shell,同時借鑒了github上面的shellpy模塊,而且我覺得go語言的go-sh確實令人喜歡,所以我覺得基於流操作將會改變我們的很多工作。

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

import shlex
from subprocess import Popen
from subprocess import PIPE


def py_ver():
    '''
    判斷python的版本
    '''
    import sys
    return sys.version_info[0]

if py_ver() == 2:
    builtin_str = str
    bytes = str
    str = unicode
    basestring = basestring
    numeric_types = (int, long, float)

elif py_ver() == 3:
    builtin_str = str
    str = str
    bytes = bytes
    basestring = (str, bytes)
    numeric_types = (int, float)
else:
    raise ValueError(u'python 版本不正確')


def parse_shell_token(t):
    import os
    # handle '~'
    t = os.path.expanduser(t)
    # handle env var
    t = os.path.expandvars(t)
    return t


def pipe_to_tmp(data):
    '''
    把管道或者內存中的數據緩存到臨時文件
    '''
    if isinstance(data, (unicode, str)):
        data = data.encode('utf-8')

    import tempfile
    stdin_tmp = tempfile.SpooledTemporaryFile()
    stdin_tmp.write(data)
    stdin_tmp.seek(0)
    return stdin_tmp


class Shell(object):

    def __init__(self, cmd_str, input_pipe=None):
        self.cmd_str = cmd_str
        self.popen = None
        self.input_pipe = input_pipe
        self.std = {'out': None, 'err': None}

    def __getPopen(self):
        if self.popen is None:
            self.popen = Popen(
                map(parse_shell_token, shlex.split(self.cmd_str, posix=False)),
                stdin=self.input_pipe, stdout=PIPE, stderr=PIPE)
        return self.popen

    def pipe(self, cmd_str):
        input_pipe = None
        pp = self.__getPopen()
        if pp.stdout.closed:
            # 如果命令已經執行,那么就把標准輸出的結果保存到臨時文件
            input_pipe = pipe_to_tmp(self.std['out'])
        else:
            input_pipe = pp.stdout
        # print input_pipe.read()
        # pp.stdout.close() # allow pp to receive SIGPIPE?
        return Shell(cmd_str, input_pipe=input_pipe)

    def __communicate(self):
        pp = self.__getPopen()
        if pp.returncode is None:
            self.std['out'], self.std['err'] = pp.communicate()

    def run(self):
        if self.std['out'] is None:
            self.__communicate()
        print self.std['out']

    def stdout(self):
        if self.std['out'] is None:
            self.__communicate()
        return self.std['out']

    def stderr(self):
        if self.std['err'] is None:
            self.__communicate()
        return self.std['err']

cmd = Shell
if __name__ == '__main__':

    # cmd('ls -l').run()
    # cmd('ls -l').pipe('grep Shell.py').run()
    # cmd('cat').pipe('> hello;cat hello').run()

    # cmd('ls ~').run()
    cmd('echo dddd').run()



下面這個是改良版本,參考了python的bash類庫的實現,僅用於學習
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from subprocess import Popen
 4 from subprocess import PIPE
 5 import shlex
 6 
 7 def py_ver():
 8     '''
 9     得到python的版本
10     '''
11     import sys
12     return sys.version_info[0]
13 _ver = py_ver()
14 
15 if _ver == 2:
16     builtin_str = str
17     bytes = str
18     str = unicode
19     basestring = basestring
20     numeric_types = (int, long, float)
21 
22 elif _ver == 3:
23     builtin_str = str
24     str = str
25     bytes = bytes
26     basestring = (str, bytes)
27     numeric_types = (int, float)
28 else:
29     raise ValueError(u'python 版本不正確')
30 del _ver
31 
32 #解析字符串中的環境變量
33 def parse_shell_token(t):
34     import os
35     #將~等用用戶的家目錄進行替換
36     t = os.path.expanduser(t)
37     #path中可以使用環境變量,'$PATH'...
38     t = os.path.expandvars(t)
39     return t
40 
41 class cmd(object):
42     def __init__(self, *args, **kwargs):
43         self.stdout = None
44         self.cmd(*args, **kwargs)
45     def cmd(self, cmd, env=None, stdout=PIPE):
46         p = Popen(parse_shell_token(cmd), shell=True,
47                   stdout=stdout, stdin=PIPE, stderr=PIPE, env=env)
48         self.stdout, self.stderr = p.communicate(input=self.stdout)
49         self.code = p.returncode
50         return self
51     def __repr__(self):
52         return self.value()
53 
54     def __unicode__(self):
55         return self.value()
56 
57     def __str__(self):
58         return self.value()
59 
60     def __nonzero__(self):
61         return self.__bool__()
62 
63     def __bool__(self):
64         return bool(self.value())
65 
66     def value(self):
67         if not self.stdout:
68             return ''
69         return self.stdout.strip()
70 
71 if __name__ == '__main__':
72     #print cmd('ls -l')
73     print cmd("ls . | grep 'pyc'")
74     #print cmd("konsole --hold -e 'konsole --help'")
75     #print cmd('scrapy list')
76     print cmd('ls $HOME')
77      #print cmd('ls ~')

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM