当使用 subprocess.Popen(args, shell=True)
运行“gcc --version
”(仅作为示例),在 Windows 上我们得到:
>>> from subprocess import Popen
>>> Popen(['gcc', '--version'], shell=True)
gcc (GCC) 3.4.5 (mingw-vista special r3) ...
所以它可以很好地打印出我所期望的版本。但在 Linux 上,我们得到了这个:
>>> from subprocess import Popen
>>> Popen(['gcc', '--version'], shell=True)
gcc: no input files
因为gcc没有收到--version
选项。
文档没有具体说明在 Windows 下 args 应该发生什么,但它确实说,在 Unix 上,“如果 args 是一个序列,第一项指定命令字符串,任何附加项将被视为额外的 shell 参数。” 恕我直言,Windows 方式更好,因为它允许您将 Popen(arglist)
调用与 Popen(arglist, shell=True )
个。
为什么这里有 Windows 和 Linux 的区别?
最佳答案
实际上在 Windows 上,当 shell=True
时它确实使用 cmd.exe
- 它预先添加 cmd.exe/c
(它实际上看起来COMSPEC
环境变量,但默认为 cmd.exe
如果不存在)到 shell 参数。 (在 Windows 95/98 上,它使用中间 w9xpopen
程序来实际启动命令。
所以奇怪的实现实际上是 UNIX
一个,它执行以下操作(每个空格分隔不同的参数):
/bin/sh -c gcc --version
看起来正确的实现(至少在 Linux 上)应该是:
/bin/sh -c "gcc --version" gcc --version
因为这会从引用的参数中设置命令字符串,并成功传递其他参数。
来自 -c
的 sh
手册页部分:
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]
关于python - 为什么带有 shell=True 的 subprocess.Popen() 在 Linux 和 Windows 上的工作方式不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1253122/