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

本文总结了Stack Overflow上关于如何使用Python调用外部命令的高赞回答,推荐使用subprocess模块,因为它比os.system更灵活且安全。文章警告了字符串参数可能带来的安全风险,并提到了其他如sh、plumbum、fabric和envoy等工具作为替代选项。
摘要由CSDN通过智能技术生成

(给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 -

推荐阅读  点击标题可跳转

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

2、原来 collections 这么好用!!

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

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值