#在Python中调用外部命令

原问题地址:http://stackoverflow.com/questions/89228/calling-an-external-command-in-python

##问题:

我如何在Python脚本内部调用外部命令(就好像我在Unix shell命令行或者在Windows命令提示符中键入外部命令那样)?

##答案 1:

参看标准函数库中的subprocess module:

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

os.system的优势在于它的灵活性更强(你可以获得标准输出、标准错误、“真实”的状态码、更好的错误处理,等等)。我认为os.system已过时或即将过时(参考阅读:https://docs.python.org/2/library/subprocess.html#replacing-older-functions-with-the-subprocess-module)

然而,os.system对于快速上手的脚本或一次性脚本是够用的。

##答案 2:

这里总结了调用外部程序的方法和每个方法的优缺点:

os.system("some_command with args")把命令和参数发送到shell。这是很好的,因为这种方式实际上可以使你同时运行多个命令、设置管道和输入/输出重定向。例如,

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

然而,虽然这样做很方便,你却必须处理转义shell中的字符,如:空格等。另一方面,这也使得你所运行的命令仅仅是shell命令,实际上并不是外部程序。 阅读材料

stream = os.popen("some_command with args")也可以实现os.system的功能,只不过它给了你一个类似文件的对象,有了这个对象,你就可以为那个进程使用标准输入/输出。对于os.popen还有3种其他的变式,它们在处理i/o的方式上略有不同。如果你把每个命令都当作字符串来传递,那么你的命令就被传递到shell;如果你把这些命令作为列表来传递,你就不必担心转义的问题。阅读材料subprocess模块的Popen类。Popen旨在替代os.popen,但它本身的综合性使它有点复杂。例如,你会使用

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

而不是

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

这些选择都是在一个统一的类中而不是在4个不同的popen函数中,这总归是好的。阅读材料

4、从subprocess模块中调用函数。这基本上就像Popen类一样,采用的都是相同的参数,但它只是等待命令完成并返回代码。例如:

return_code = subprocess.call("echo Hello World", shell=True)

阅读材料

5、如果你使用的是Python 3.5或更高版本,你可以使用新的subprocess.run功能。subprocess.run和以上的方法很像,但更灵活,而且当命令执行完毕时,返回CompletedProcess对象。fork/exec/spawn功能,但我不建议直接使用它们。

也许你应该使用的是subprocess模块。

最后,请注意:在所有的方法中,你把最终命令作为一个字符串发送到shell来执行的时候,你就要负责对它进行转义。如果你所发送的任何部分的字符串不能完全被信任,就会有严重的安全隐患。(例如,如果用户正在确认执行某一部分或任何部分的字指令)。如果你不确定,只使用这些带有常量的方法。为了对这些隐患稍作了解,考虑一下这个代码

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

想象一下,用户执行“my mama didnt love me && rm -rf /”。