Python和shell script是目前编写脚本类应用的不二之选,在纠结使用Python还是shell script时,希望本文能够提供一些思路。
Python和shell script对比
Python最突出的优势在于语言相对简单,熟悉的人多,支持json解析等高级语言特性。
shell的优势在于特定场景下代码更简练,ps,grep,awk,sed,tar等命令一行能够搞定的场景,如果用python原生代码来实现相对会比较复杂,而且往往还需要安装第三方Python库。
在部署方式上两者区别都不大,python和shell大部分情况下使用“原生库”即可搞定。
Python的原生库subprocess支持调用shell script命令,选择Python + subprocess库的方案可以结合两者的优势,这是我为什么推荐用Python代替shell脚本的原因
subprocess注意事项
兼容性
subprocess库有多个版本,需兼容不同的版本。核心代码如下:
def check_output(cmd):
"""
execute shell commandline, return output
:param cmd: commandline string
:return:
output string: empty string if output nothing. For shell command, the output has a "\n" in the end generally.
None: failed to execute the commandline, do not use None to judge whether the execution result is ok.
"""
if hasattr(subprocess, 'check_output'):
try:
p = subprocess.check_output(cmd, shell=True)
if isinstance(p, bytes):
return p.decode()
else:
return p
except subprocess.CalledProcessError as e:
print(e)
return None
else:
# python version < 2.7
try:
output = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True).communicate()[0]
return output
except subprocess.CalledProcessError as e:
print(e)
return None
grep命令的返回值
grep查找失败时,subprocess在python3中会直接抛出异常,这与shell的习惯不同。以如下代码举例:
if grep abc check_process.sh ;
then
echo good
fi
这是shell中的典型写法,判断check_process.sh文件中是否存在abc字符串,使用subprocess实现的话,代码一般如下:
if __name__ == "__main__":
r = check_output("grep abc check_process.sh")
if "abc" in r:
print "good"
当grep查找失败时,返回值是1。在python3中会抛出异常,返回None,而不是空字符串,此时在命令尾部增加 “|| true”即可,请注意在这种情况下,即使命令执行失败也不会返回None,比如check_process.sh不存在时也会返回空字符串。
r = check_output("grep abc check_process.sh || true")
非预期输出
命令的输出会与脚本输出混杂在一起,比如grep的结果会直接输出到stdout。我们当然可以通过重定向到/dev/null的方式来处理,但是总会有漏网之鱼。如果脚本最终要输出格式化的数据,建议输出到文件中,而不是stdout。
最佳实践推荐
- Python中调用subprocess集成shell脚本
- 使用单元测试
- 使用getopt库处理入参
- 支持格式化输出,比如json。结果输出到文件,而不仅仅是stdout。
- 关注脚本的退出code, sys.exit()返回值应体现出脚本执行结果。
如果对你有帮助,请顺手点个赞