为什么shell = True的subprocess.Popen()在Linux和Windows上的工作方式不同? [英] Why does subprocess.Popen() with shell=True work differently on Linux vs Windows?

查看:214
本文介绍了为什么shell = True的subprocess.Popen()在Linux和Windows上的工作方式不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用subprocess.Popen(args, shell=True)运行"gcc --version"(仅作为示例)时,在Windows上我们得到以下信息:

When using subprocess.Popen(args, shell=True) to run "gcc --version" (just as an example), on Windows we get this:

>>> from subprocess import Popen
>>> Popen(['gcc', '--version'], shell=True)
gcc (GCC) 3.4.5 (mingw-vista special r3) ...

因此,按我的期望很好地打印了版本.但是在Linux上,我们得到以下信息:

So it's nicely printing out the version as I expect. But on Linux we get this:

>>> from subprocess import Popen
>>> Popen(['gcc', '--version'], shell=True)
gcc: no input files

因为gcc尚未收到--version选项.

Because gcc hasn't received the --version option.

文档没有确切指定Windows下的args应该发生什么,但是它确实说在Unix上,"如果args是一个序列,则第一项指定命令字符串,任何其他项将恕我直言,Windows方法更好,因为它允许您将Popen(arglist)调用与Popen(arglist, shell=True)调用一样对待.

The docs don't specify exactly what should happen to the args under Windows, but it does say, on Unix, "If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional shell arguments." IMHO the Windows way is better, because it allows you to treat Popen(arglist) calls the same as Popen(arglist, shell=True) ones.

为什么Windows和Linux在这里有区别?

推荐答案

实际上,在Windows上,当shell=True时它确实使用cmd.exe-它在cmd.exe /c之前加上(实际上是查找COMSPEC环境变量,但默认为到cmd.exe(如果不存在的话)). (在Windows 95/98上,它使用中间的w9xpopen程序实际启动命令).

Actually on Windows, it does use cmd.exe when shell=True - it prepends cmd.exe /c (it actually looks up the COMSPEC environment variable but defaults to cmd.exe if not present) to the shell arguments. (On Windows 95/98 it uses the intermediate w9xpopen program to actually launch the command).

所以奇怪的实现实际上是UNIX,它执行以下操作(其中每个空格分隔一个不同的参数):

So the strange implementation is actually the UNIX one, which does the following (where each space separates a different argument):

/bin/sh -c gcc --version

看起来正确的实现(至少在Linux上是)

It looks like the correct implementation (at least on Linux) would be:

/bin/sh -c "gcc --version" gcc --version

因为这将通过引用的参数设置命令字符串,并成功传递其他参数.

Since this would set the command string from the quoted parameters, and pass the other parameters successfully.

-c手册页的-c部分:

Read commands from the command_string operand instead of from the standard input. Special parameter 0 will be set from the command_name operand and the positional parameters ($1, $2, etc.) set from the remaining argument operands.

此补丁似乎很简单:

--- subprocess.py.orig  2009-04-19 04:43:42.000000000 +0200
+++ subprocess.py       2009-08-10 13:08:48.000000000 +0200
@@ -990,7 +990,7 @@
                 args = list(args)

             if shell:
-                args = ["/bin/sh", "-c"] + args
+                args = ["/bin/sh", "-c"] + [" ".join(args)] + args

             if executable is None:
                 executable = args[0]

这篇关于为什么shell = True的subprocess.Popen()在Linux和Windows上的工作方式不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆