Python从Shell提取版本号:安全方法及StrictVersion报错解决
解决Ansible版本检测中的subprocess安全问题与StrictVersion错误
咱们先拆解你遇到的两个核心问题,一步步解决:
1. AttributeError的根源:subprocess.call返回的不是命令输出
你用subprocess.call()执行命令时,它返回的是命令的退出状态码(0表示执行成功,非0代表失败),而不是命令打印到终端的内容。所以你看到终端输出了1.2.3,但print version其实输出的是0——把整数传给StrictVersion自然会触发错误,因为它需要的是字符串格式的版本号,不是数字。
2. 替换shell=True的安全替代方案
使用shell=True确实存在shell注入风险(尤其是当命令包含用户可控内容时)。更好的做法是直接调用ansible命令,在Python代码里自己解析输出,完全摆脱对shell管道(grep、awk)的依赖。
修正后的Python 2.7代码
import subprocess import re from distutils.version import StrictVersion def updateAnsible(): print 'Checking Ansible version' try: # 直接调用ansible命令,不依赖shell,捕获输出内容 output = subprocess.check_output(["ansible", "--version"], stderr=subprocess.STDOUT) # 用正则匹配版本号:精准抓取"ansible "后的x.y.z格式字符串 version_match = re.search(r'ansible (\d+\.\d+\.\d+)', output) if not version_match: print "Failed to parse Ansible version" return version_str = version_match.group(1) print "Current Ansible version:", version_str # 用StrictVersion做版本比较 if StrictVersion(version_str) < StrictVersion('2.7.0'): print "Need to upgrade" else: print "Do not need to upgrade" except subprocess.CalledProcessError as e: print "Error running ansible --version:", e.output except Exception as e: print "Unexpected error:", str(e) if __name__ == '__main__': updateAnsible()
关键改进点说明:
- 移除shell=True:直接传递命令参数列表
["ansible", "--version"],彻底避免shell注入风险,同时让subprocess直接执行命令,效率更高。 - 正确捕获输出:用
subprocess.check_output()获取命令的标准输出,命令执行失败时会抛出CalledProcessError,方便我们捕获异常并处理。 - Python内建解析逻辑:用正则表达式匹配版本号,比依赖shell工具更灵活可控,还能适配ansible输出格式的小变动。
- 增加异常处理:避免因为ansible未安装、命令执行失败等意外情况导致脚本直接崩溃。
额外提示
如果之后升级到Python 3,推荐使用更清晰的subprocess.run()API替代check_output():
result = subprocess.run(["ansible", "--version"], capture_output=True, text=True) output = result.stdout
内容的提问来源于stack exchange,提问作者bc81
相关产品推荐
相关产品推荐

