胡琪

为今天工作,为明天投资,为未来孵化一些东西!

从Wnidows迁移到linux系统引起的bug谈谈python中subprocess.Popen的shell参数

最近在将某个window系统上的python脚本迁移到linux服务器上进行测试的时候发现原本在window运行好好的工程在linux上却出现了问题,不能达到预期执行效果。通过日志可以判断出是在使用python的subprocess.Popen执行某个java命令的时候未生效导致的。当时百思不其解,因为这个工程在window上已经运行过很多次了,是可以正常工作的,为何迁移到linux上就不能正常工作了呢?

在项目的Utils.py模块中有如下的一个函数用来使用subprocess.Popen执行某个命令

然后在其他调用模块存在如下一段调用代码

这段调用代码就是使用Utils模块中的executeCmd函数来执行一个java -jar的命令调用asmtool.jar这个jar包完成某个操作。这段调用在windows上是没问题的,能够正确被执行,但是把该工程迁移到linux服务器上后运行会发现当脚本运行到

一行后返回值ret_code不为0,也就是说该命令未被正确执行,而通过executeCmd打印出来的log来看传入的cmd参数确实是

也就是说传入的命令是正确的,但是该命令在windows可以被正确执行,但是在linux上不能被正确执行,当时就感到很奇怪了,后来详细看了下python官方文档对subprocess.Popen类的详细描述才发现原来是Popen类的shell参数导致的。官方文档地址:https://docs.python.org/2/library/subprocess.html#popen-constructorPopen类的构造函数的详细定义如下:

参数很多,我们常用参数及其意义如下:

  • args 要执行的命令参数,可以是序列或者单个的字符串,官方推荐使用序列
  • bufsize 缓冲区大小,0无缓冲,1行缓冲,其他正值表示缓冲区大小,负值则使用系统默认的大小
  • stdin 标准输入
  • stdout 标准输出
  • stderr标准错误,可以为subprocess.STDOUT
  • shell 是否使用shell程序来执行,默认为false,如果设置为true,官方推荐传递args时传递字符串而不是序列

而正是这个不起眼的shell参数导致了上述命令在win下可以正确执行而在linux上无法正确执行。当shell参数被设置为了true的话(如本例Utils模块),则在windows系统上相当于在args参数前添加了“cmd.exe /c”,在linux上相当于在args参数前添加了“/bin/sh”,”-c”。也就是说如果设置为true则相当于在参数前添加了相应系统的执行脚本程序。因此如果此时传入的args参数是序列的话,如本例的列表

因为在window系统上如果传入参数是列表,最终将转化为字符串(On Windows, if args is a sequence, it will be converted to a string in a manner described in Converting an argument sequence to a string on Windows. This is because the underlying CreateProcess() operates on strings.)转换规则大致就是以空格分割,因此在windows上最终调用会转换为:

因此在window上上述示例是可以正确被执行的,但是在liunx上如果传入的参数是序列同时shell设置为true的话,则最终调用会转为

即本实例在linux上最终调用是

而这种调用很明显是错误的,大家可以用任何一个jar包做个测试,如图:

《从Wnidows迁移到linux系统引起的bug谈谈python中subprocess.Popen的shell参数》

可以看到输出是java的usage输出,也就是说调用java -jar命令失败,换而言之当我们将shell参数设置为true的时候传入的args参数最好是字符串而不是序列,像下面这种形式:

此时如果shell参数为true且在linux上则最终调用会转换为:

这种调用很明显就是正确的了。

或者如果定义的是list类型则在传入给Popen前先将其转换为字符串类型

然后在linux系统上就可以像这样调用了:

总结

  • Popen的shell参数最好设置为false(这也是默认设置)
  • Popen的args参数最好传入序列,如lsit,这也是官方推荐方式
  • 如果Popen的shell参数设置为了true,则在linux上args参数最好传递字符串,windows上随意
打赏

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注