简体   繁体   English

subprocess.Popen给出随机结果

[英]subprocess.Popen gives random result

I wrote a simple piece of code: 我写了一段简单的代码:

import subprocess
p=subprocess.Popen('mkdir -p ./{a,b,c}', shell=True, stderr=subprocess.STDOUT)
p.wait()

Unfortunately, it not always behaves the way I'd expect. 不幸的是,它并不总是表现出我所期望的。 Ie, when I run it on my PC, everything is OK (ls -l gives me three dirs: a, b and c). 即,当我在PC上运行它时,一切正常(ls -l给出了三个目录:a,b和c)。 But when my colleague runs it on his desktop, he gets... one dir named: '{a,b,c}' ... We both use Python 2.7.3. 但是当我的同事在他的桌面上运行它时,他得到了……一个目录名为:“ {a,b,c}”……我们俩都使用Python 2.7.3。 Why is that? 这是为什么? How would you fix it? 您将如何解决?

I tried to find the answer by myself. 我试图自己找到答案。 According to manual: "args should be a sequence of program arguments or else a single string. By default, the program to execute is the first item in args if args is a sequence. If args is a string, the interpretation is platform-dependent and described below. See the shell and executable arguments for additional differences from the default behavior. Unless otherwise stated, it is recommended to pass args as a sequence." 根据手册:“ args应该是程序参数的序列,或者是单个字符串。默认情况下,如果args是序列,则要执行的程序是args中的第一项。如果args是字符串,则解释取决于平台如下所述。有关默认行为的其他区别,请参见shell和可执行参数。除非另有说明,否则建议将args作为序列传递。”

So I tried to execute the code in shell: 所以我尝试在shell中执行代码:

python -c "import subprocess; p=subprocess.Popen(['mkdir', '-p', './{ea,fa,ga}'], shell=True, stderr=subprocess.STDOUT); p.wait()"

And I got: 我得到:

mkdir: missing operand

I will be thankful for any advice 我将感谢您的任何建议

Thanks! 谢谢!

The ./{a,b,c} syntax is bash syntax, not supported by all shells. ./{a,b,c}语法是bash语法,并非所有shell都支持。

The documentation says: 该文件说:

On Unix with shell=True , the shell defaults to /bin/sh . shell=True Unix上,shell默认为/bin/sh If args is a string, the string specifies the command to execute through the shell. 如果args是字符串,则该字符串指定要通过外壳执行的命令。

So your command only works if /bin/sh is symlinked to a shell that supports that syntax, like bash or zsh . 因此,只有将/bin/sh符号链接到支持该语法的shell(例如bashzsh ,该命令才有效。 Your colleague is probably using dash or another shell that doesn't support this. 您的同事可能正在使用dash或其他不支持此功能的外壳。

You should no be relying in something like a user's default shell. 您不应该依赖用户的默认外壳之类的东西。 Instead, write the full command with the full expansion: 相反,编写带有完整扩展的完整命令:

p = subprocess.Popen('mkdir -p ./a ./b ./c', shell=True, stderr=subprocess.STDOUT)

There's several problems here. 这里有几个问题。

  • First: if you are using a sequence of arguments, do not set "shell = True" ( this is recommended in the Popen manual) . 首先:如果使用一系列参数,请不要设置“ shell = True”( 在Popen手册中建议这样做 Set it to False, and you'll see that your mkdir command will be accepted. 将其设置为False,您将看到您的mkdir命令将被接受。
  • "./{a,b,c}" is AFAIK a specific syntax in bash. “ ./{a,b,c}”是AFAIK bash中的一种特定语法。 If your colleague is using a different shell, it will probably not work, or behave differently. 如果您的同事使用其他外壳,则可能无法正常工作或表现不同。
  • You should use the python "mkdir" command instead of calling a shell command, it will work whatever the server / shell / OS. 您应该使用python“ mkdir”命令而不是调用shell命令,它可以在任何服务器/ shell / OS上运行。

Thank you all for your answers. 谢谢大家的答案。 It seems, that the best way is simply use /bin/sh syntax. 看来,最好的方法就是简单地使用/ bin / sh语法。 I changed my code to use: 我更改了代码以使用:

'mkdir -p ./a ./b ./c'

as you suggested. 如您所建议。

I avoided to use mkdir() function, because I am writing a scripts with plenty of system calls, and I wanted to provide elegant --dry-run option (so I could list all of the commands). 我避免使用mkdir()函数,因为我正在编写带有大量系统调用的脚本,并且我想提供优雅的--dry-run选项(以便我可以列出所有命令)。

Problem solved - thank you! 问题已解决-谢谢!

The os.mkdir(path,[mode]) method are as far as I understand safer to use when working on multiplatform projects. 据我了解,在处理多平台项目时,os.mkdir(path,[mode])方法更安全。

os.mkdir(os.getcwd()/a)

However its not as elegant as taking the subprocess approach. 但是,它不如采用子过程方法那样优雅。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM