用Python代替shell脚本

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。

最佳实践推荐

  1. Python中调用subprocess集成shell脚本
  2. 使用单元测试
  3. 使用getopt库处理入参
  4. 支持格式化输出,比如json。结果输出到文件,而不仅仅是stdout。
  5. 关注脚本的退出code, sys.exit()返回值应体现出脚本执行结果。

如果对你有帮助,请顺手点个赞

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容