查看原文
其他

Stack Overflow 热帖:如何用 Python 调用外部命令

Python开发者 Python开发者 2021-02-01

(给Python开发者加星标,提升Python技能

问题


也许大家在日常工作中遇到过要用 Python 脚本执行外部命令的情况,并且你还不知道怎么调用。


没关系,早在 12 年前就有程序员在 Stack Overflow 上求助提问啦。



本文为大家总结整理其中一些高赞回答,以备不时之需!


解决方法


方法1:我们可以使用 subprocess ,比如要执行 ls -l 命令

import subprocess subprocess.run(["ls", "-l"])

Python3.5 之前的版本,需要使用 call

import subprocess subprocess.call(["ls", "-l"])

方法2:

import os os.system("ls -l") #执行命令os.popen("ls -l").read() #执行并输出命令的执行结果

方法讨论:


问题解决了,那么os.system 和 subprocess 那个解决方法更好一点呢?这里做简单讨论,虽然os.system 和 subprocess 都能完成调用外部命令的功能,但是subprocess 比 system 更灵活(subprocess 我们可以得到 stdout,stderr 以及更好的错误处理等等)。并且官方文档也是更建议 subprocess 模块。


下面是对各种调用外部程序的方法的小总结:


1、os.system("some_command with args"):将命令和参数传给系统shell,这个方法可以一次执行多条命令,并且可以建立管道重定向例如:

os.system("some_command < input_file | another_command > output_file")

尽管这种方式很简便,但是你不得不手工处理一些特殊字符例如空格等。


2、stream=os.popen("some_command with args"):实现的功能和os.system是一样的,但是os.popen会返回一个类文件对象,让你看到命令的执行结果。

stream=os.popen("ls -l")stream.read() #输出ls -l 的结果

3、subprocess的Popen类,建议尽量使用它来代替os.popen,但是使用的时候参数会相对复杂,例如

print(subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read())

而不建议使用

print(os.popen("echo Hello World").read())

4、subprocess模块中的call函数,功能和Popen类相似,并且使用相同的参数,但是它仅仅在命令执行完毕后,返回一个代码,例如

return_code = subprocess.call("echo Hello World", shell=True)0 #执行成功

5、如果使用的是Python3.5及以上版本,可以使用subprocess.run函数,它跟上面介绍的函数基本一样,但是更灵活,会在命令行执行结束后返回一个CompletedProcess对象。

return_code = subprocess.run("echo Hello World", shell=True)return_codeCompletedProcess(args='echo Hello World', returncode=0) #CompletedProcess对象type(return_code)

6、虽然os模块包括fork/exec/spawn等函数,但是并不建议直接使用它们,使用不当可能会导致意外结果。


因此如果有需要执行外部命令的需要,建议使用subprocess,而非os模块。


最后,特别要注意如果你要执行的命令是以字符串的形式作为参数,那么必须小心谨慎,否则会造成严重的后果!比如下面的例子

print(subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read())

看到这段代码能想到什么可怕的事情吗?如果有人给 user_input 传递的是 "my mama didnt love me && rm -rf /",是不是头皮发麻! 所以谨慎再谨慎!!尽量不做交互式输入,而是在程序中,将要执行的命令,写“死”在字符串中,做为常量传递。


拓展思路


下面还整理了一些其它的方法,有兴趣的同学可再深入研究。


sh


sh程序是subprocess的接口,让你像调用函数一样的调用想执行的程序。如果要多次运行一个命令,这很有用。

sh.ls("-l") ls_cmd = sh.Command("ls")

plumbum


plumbum功能和sh类似。

ls_cmd = plumbum.local("ls -l") ls_cmd()

fabric


fabric 是py2.5和2.7的库。可以让你执行本地或远程shell命令。

fabric.operations.local('ls -l')fabric.operations.local('ls -l', capture = True)

envoy


envoy 以“subprocess for humans”闻名,它是对subprocess模块的封装,简单易用

r = envoy.run("ls -l") r.std_out


参考链接:

https://stackoverflow.com/questions/89228/how-to-call-an-external-command


关于调用外部命令,你们是在用哪种方法呢?欢迎在评论中和我探讨。觉得文章不错,请点赞和在看支持我继续分享好文。谢谢!



- EOF -

推荐阅读  点击标题可跳转

1、如何返回一个 List 中某元素的索引?

2、原来 collections 这么好用!!

3、GitHub 标星 7.4k!Python 魔法库之 FuzzyWuzzy


觉得本文对你有帮助?请分享给更多人

关注「Python开发者」加星标,提升Python技能

点赞和在看就是最大的支持❤️

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存