(给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_code
CompletedProcess(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 -
推荐阅读 点击标题可跳转
3、GitHub 标星 7.4k!Python 魔法库之 FuzzyWuzzy
觉得本文对你有帮助?请分享给更多人
关注「Python开发者」加星标,提升Python技能
点赞和在看就是最大的支持❤️