python显示外部命令_在Python中调用外部命令

我如何从Python脚本中调用一个外部命令(就像我在Unix shell或Windows命令提示符下键入的那样)?

答案

查看标准库中的子进程模块:

fromsubprocessimportcall

call(["ls", "-l"])

子进程 vs 系统的优点是它更加灵活(你可以得到stdout,stderr,“真实”状态码,更好的错误处理等等)。

在官方文档建议子模块在替代使用os.system():

该子模块提供了产卵新的流程和检索其结果更加强大的工具; 使用该模块优于使用该函数[ os.system()]。

该“ 与子模块更换旧的功能中”部分子文档可能有一些有益的食谱。

有关子流程模块的官方文档:

以下是调用外部程序的方法以及每种方法的优缺点的总结:

os.system("some_command with args")将命令和参数传递给你的系统的shell。这很好,因为你可以用这种方式一次运行多个命令,并设置管道和输入/输出重定向。例如:

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

但是,虽然这很方便,但您必须手动处理诸如空格等外壳字符的转义。另一方面,这也可以让您运行仅仅是shell命令的命令,而不是实际上的外部程序。请参阅文档。

stream = os.popen("some_command with args")将会做同样的事情,os.system只不过它提供了一个类似文件的对象,您可以使用它来访问该进程的标准输入/输出。还有另外三种popen变体,它们都以不同的方式处理I / O。如果你把所有东西都作为一个字符串传递,那么你的命令被传递给shell; 如果你将它们作为列表传递给你,那么你不需要担心逃脱任何事情。请参阅文档。

模块的Popen类subprocess。这是为了取代它,os.popen但由于其如此全面而略微复杂一些,因此它的缺点是。例如,你会说:

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

代替:

printos.popen("echo Hello World").read()

但是在一个统一的类中有所有的选项,而不是4个不同的popen函数是很好的。请参阅文档。

call来自subprocess模块的功能。这基本上和Popen类一样,并且采用了所有相同的参数,但它只是等到命令完成并给出返回码。例如:

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

请参阅文档。

如果您使用的是Python 3.5或更高版本,则可以使用新subprocess.run函数,这与上述类似,但更加灵活,并CompletedProcess在命令执行完成时返回对象。

os模块还具有C程序中所有的fork / exec / spawn函数,但我不建议直接使用它们。

该subprocess模块应该可能是你使用的。

最后请注意,对于所有通过shell以字符串形式执行的最终命令的方法,您负责转义它。如果您传递的字符串的任何部分无法完全信任,则存在严重的安全隐患。例如,如果用户正在输入字符串的某个/任何部分。如果您不确定,请仅使用这些方法和常量。为了给你一些暗示,请考虑下面的代码:

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

并想象用户输入“我的妈妈没有爱我&& rm -rf /”。

我通常使用:

importsubprocess

p=subprocess.Popen('ls',shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)

forlineinp.stdout.readlines():

printline,retval=p.wait()

您可以随意使用stdout管道中的数据执行任何操作。事实上,你可以简单地忽略这些参数(stdout=和stderr=),它的行为就像os.system()。

关于从调用者中分离子进程的一些提示(在后台启动子进程)。

假设你想从一个CGI脚本开始一个长任务,那就是子进程应该比CGI脚本的执行过程长。

子流程模块文档中的经典示例是:

importsubprocessimportsys# some code herepid=subprocess.Popen([sys.executable, "longtask.py"]) # call subprocess

# some more code here

这里的想法是,你不想在’call subprocess’行中等待,直到longtask.py完成。但是不清楚在这个例子中’这里有更多的代码’之后会发生什么。

我的目标平台是freebsd,但是开发是在Windows上进行的,所以我首先面对Windows上的问题。

在Windows(win xp)上,父进程将不会完成,直到longtask.py完成其工作。这不是你想要的CGI脚本。这个问题不是特定于Python,在PHP社区中,问题是相同的。

解决方案是在win API中将DETACHED_PROCESS 进程创建标志传递给底层的CreateProcess函数。如果你碰巧安装了pywin32,你可以从win32process模块​​导入标志,否则你应该自己定义它:

DETACHED_PROCESS= 0x00000008pid=subprocess.Popen([sys.executable, "longtask.py"],creationflags=DETACHED_PROCESS).pid

/ * UPD 2015.10.27 @eryksun在下面的注释中注意到,语义上正确的标志是CREATE_NEW_CONSOLE(0x00000010)* /

在freebsd上,我们遇到了另一个问题:当父进程完成时,它也完成了子进程。这并不是你想要的CGI脚本。一些实验表明,这个问题似乎是在共享sys.stdout。工作解决方案如下:

pid=subprocess.Popen([sys.executable, "longtask.py"],stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE)

我没有检查过其他平台上的代码,也不知道freebsd上的行为原因。如果有人知道,请分享您的想法。在Python中开始后台进程的搜索并没有任何亮点。

我建议使用子进程模块而不是os.system,因为它为你的shell进行转义,因此更安全:http://docs.python.org/library/subprocess.html

subprocess.call(['ping', 'localhost'])

importos

cmd= 'ls -al'os.system(cmd)

如果你想返回命令的结果,你可以使用os.popen。不过,从版本2.6开始,这被弃用,以支持子流程模块,其他答案已经涵盖得很好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值