获取subprocess执行返回值 解决ping连通性测试自定义函数运行异常问题
现存问题梳理
- 直接在
subprocess.Popen的args参数中写管道符|无法生效:管道是shell提供的功能,默认执行模式下Popen会把|当成普通参数传给ping命令,无法实现你想要的结果过滤效果。 - 命令参数拆分错误:
grep -E -o、"[0-9]+ received"、cut -f1 -d这些写法不符合args的拆分规则,每个空格分隔的参数都要单独作为元组的元素,且cut的-d参数没有指定分隔符(此处应该是空格)。 - 逻辑判断错误:
if (popen == 1)完全不符合逻辑,popen是进程对象,不是执行结果,你需要读取进程的标准输出内容做判断。 - 冗余的sudo权限:ping命令普通用户即可执行,不需要加sudo提升权限。
修正方案
方案1:开启shell支持,适配小工具场景
如果是个人使用的小工具,可以直接开启shell=True支持管道语法,写法更简洁:
import subprocess def testConnection(ip): TIMEOUT = 10 # 整段命令作为字符串传入 cmd = f"ping -c 1 -q {ip} | grep -E -o '[0-9]+ received' | cut -f1 -d' '" try: popen = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) stdout, stderr = popen.communicate(timeout=TIMEOUT) recv_count = stdout.strip() if recv_count == '1': print(ip + " is up") return True else: print(ip + " is down") return False except subprocess.TimeoutExpired as e: print(e) popen.kill() return False finally: if popen.returncode != 0 and recv_count != '0': # 需提前自定义ServiceException raise ServiceException()
方案2:无外部依赖,适配生产场景
如果是生产环境使用,不建议开启shell=True(存在命令注入风险),可以直接用Python正则解析ping的输出,不需要调用grep、cut:
import subprocess import re def testConnection(ip): TIMEOUT = 10 args = ('ping', '-c', '1', '-q', ip) recv_pattern = re.compile(r'(\d+) received') try: popen = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) stdout, stderr = popen.communicate(timeout=TIMEOUT) match = recv_pattern.search(stdout) if match and match.group(1) == '1': print(ip + " is up") return True else: print(ip + " is down") return False except subprocess.TimeoutExpired as e: print(e) popen.kill() return False finally: if popen.returncode != 0 and not (match and match.group(1) == '0'): raise ServiceException()
内容的提问来源于stack exchange,提问作者Fabian
相关产品推荐
相关产品推荐

