-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathpython_run_shell.py
More file actions
211 lines (191 loc) · 6.5 KB
/
python_run_shell.py
File metadata and controls
211 lines (191 loc) · 6.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#!/usr/local/bin/python
#-*- coding: UTF-8 -*-
# subwork
__author__ ="tommy ([email protected])"
__date__ ="2009-01-06 16:33"
__copyright__="Copyright 2009 tudou, Inc"
__license__ ="Td, Inc"
__version__ ="0.1"
import os
import time
import signal
import tempfile
import traceback
import subprocess
#此包对于进行shell命令的延时处理使用的是非多线程机制(相对EasyProcess这个python包),使用所有包和函数均为python基本包,显示的封装成两个函数,解决的问题是新增命令超时的设置方法,解决了其他方法的僵尸进程的问题.
#
#1.shell_2_tty(_cmd=cmds, _cwd=None, _timeout=10*60)
#_cmd 是要执行的外面命令行,要是一个 list, 如果是str,shell=True,会启动一个新的shell去干活的,这样,不利于进程的控制
#_cwd 是执行这个命令行前,cd到这个路径下面,这个,对我的用应很重要,如果不需要可以用默认值
#_timeout 这个是主角,设置超时时间(秒单位),从真重执行命令行开始计时,墙上时间超过 _timeout后,父进程会kill掉子进程,回收资源,并避免产生 zombie(僵尸进程)并将调用的命令行输出,直接输出到stdout,即是屏幕的终端上,(如果对输出比较讨厌,可以将 stdout = open("/dev/null", "w"), stderr=open("/dev/null"),等等)
#
#2.shell_2_tempfile(_cmd=cmds, _cwd=None, _timeout=10)
#类同1,主要是增加,对命令行的输出,捕获,并返回给父进程,留作分析
__all__ = ["subwork", "trace_back", "os", "time", "traceback", "subprocess", "signal"]
def trace_back():
try:
type, value, tb = sys.exc_info()
return str(''.join(traceback.format_exception(type, value, tb)))
except:
return ''
def getCurpath():
try:
return os.path.normpath(os.path.join(os.getcwd(),os.path.dirname(__file__)))
except:
return
class subwork:
"""add timeout support!
if timeout, we SIGTERM to child process, and not to cause zombie process safe!
"""
def __init__(self, stdin=None, stdout=None, stderr=None, cmd=None, cwd=None, timeout=5*60*60):
"""default None
"""
self.cmd = cmd
self.Popen = None
self.pid = None
self.returncode= None
self.stdin = None
self.stdout = stdout
self.stderr = stderr
self.cwd = cwd
self.timeout = int(timeout)
self.start_time= None
self.msg = ''
def send_signal(self, sig):
"""Send a signal to the process
"""
os.kill(self.pid, sig)
def terminate(self):
"""Terminate the process with SIGTERM
"""
self.send_signal(signal.SIGTERM)
def kill(self):
"""Kill the process with SIGKILL
"""
self.send_signal(signal.SIGKILL)
def wait(self):
""" wait child exit signal,
"""
self.Popen.wait()
def free_child(self):
"""
kill process by pid
"""
try:
self.terminate()
self.kill()
self.wait()
except:
pass
def run(self):
"""
run cmd
"""
print "[subwork]%s" % split_cmd(self.cmd)
code = True
try:
self.Popen = subprocess.Popen(args=split_cmd(self.cmd), stdout=self.stdout, stderr=self.stderr, cwd=self.cwd)
self.pid = self.Popen.pid
self.start_time = time.time()
while self.Popen.poll() == None and (time.time() - self.start_time) < self.timeout :
time.sleep(1)
#print "running... %s, %s, %s" % (self.Popen.poll(), time.time() - self.start_time, self.timeout)
except:
self.msg += trace_back()
self.returncode = -9998
code = False
print "[subwork]!!error in Popen"
# check returncode
if self.Popen.poll() == None: # child is not exit yet!
self.free_child()
self.returncode = -9999
else:
self.returncode = self.Popen.poll()
# return
return {"code":code,\
"msg":self.msg,\
"req":{"returncode":self.returncode},\
}
def split_cmd(s):
"""
str --> [], for subprocess.Popen()
"""
SC = '"'
a = s.split(' ')
cl = []
i = 0
while i < len(a) :
if a[i] == '' :
i += 1
continue
if a[i][0] == SC :
n = i
loop = True
while loop:
if a[i] == '' :
i += 1
continue
if a[i][-1] == SC :
loop = False
m = i
i += 1
#print a[n:m+1]
#print ' '.join(a[n:m+1])[1:-1]
cl.append((' '.join(a[n:m+1]))[1:-1])
else:
cl.append(a[i])
i += 1
return cl
def check_zero(dic=None):
"""
check returncode is zero
"""
if not isinstance(dic, dict):
raise TypeError, "dist must be a Distribution instance"
print "returncode :", int(dic["req"]["returncode"])
if int(dic["req"]["returncode"]) == 0:
return True, dic["msg"]
else:
return False, dic["msg"]
def shell_2_tty(_cmd=None, _cwd=None, _timeout=5*60*60):
"""
"""
try:
shell=subwork(cmd=_cmd, stdout=None, stderr=None, cwd=_cwd, timeout=_timeout)
return check_zero(shell.run())
except:
return False, trace_back()
def shell_2_tempfile(_cmd=None, _cwd=None, _timeout=5*60*60):
"""
to collect out-string by tempfile
"""
try:
try:
fout=tempfile.TemporaryFile()
ferr=tempfile.TemporaryFile()
shell=subwork(cmd=_cmd, stdout=fout, stderr=ferr, cwd=_cwd, timeout=_timeout)
req=check_zero(shell.run())
# get media info from tmp_out
fout.seek(0)
out=fout.read()
if not out:
ferr.seek(0)
out=ferr.read()
#
return req[0], str(out)
finally:
fout.close()
ferr.close()
except:
return False, trace_back()
#---------------------------------------------
# main-test
#---------------------------------------------
if __name__ == '__main__' :
pass
cmds = "ping www.google.cn"
cmds = "ls -la"
#print shell_2_tty(_cmd=cmds, _cwd=None, _timeout=10)
print shell_2_tempfile(_cmd=cmds, _cwd=None, _timeout=10)
print "\nexit!"
time.sleep(60)