为什么子进程默认使用列表而不是带空格的字符串?

时间:2016-10-27 23:59:02

标签: python subprocess

为什么Python的subprocess模块默认将参数作为列表?为什么不是带空格的字符串(类似于在正常运行命令时键入终端的内容)的默认输入?有很多来源解释如何将命令的空格分隔字符串传递给subprocess,但不清楚为什么默认情况不是相反的。

2 个答案:

答案 0 :(得分:2)

TL; DR使用列表绕过shell,这样您就不必担心shell会以您不想要的方式解释动态构造的命令行。

假设您有一个非常简单的命令:echo foo。在这里,使用字符串和列表:

Popen("echo foo", shell=True)
Popen(["echo", "foo"])

差别不大。现在假设参数包含用于保护空格和/或shell模式的引号,echo "foo * bar"

Popen("echo \"foo   *    bar\"", shell=True)
Popen(["echo", "foo   *    bar"])

是的,我可以使用单引号来避免需要转义双引号,但是你可以看到列表形式开始有优势。现在假设我没有该命令的文字参数,但它存储在一个变量中。 现在您要使用哪个...

此?

Popen('echo "%s"' % (x,), shell=True)

还是这个?

Popen(["echo", x])

如果您回答“第一个”,则此处为x

的值
x = "\";rm -rf \""

您刚刚执行的命令是echo ""; rm -rf/""。您需要确保x值中的任何特殊字符首先被转义,然后将其合并到您要构建的字符串中以传递给shell。

或者您只需使用一个列表并完全避免使用shell。

答案 1 :(得分:-1)

忘记我写的所有内容 - 只需自己阅读相关的PEP

https://www.python.org/dev/peps/pep-0324/

===============

我的简短猜测 - 无shell列表版本更接近最终传递给POSIX nameVal命令的格式。它需要较少的操作。 shell字符串方法属于Windows遗留问题。

=====================

所以你问为什么forking案例是默认的?

  

在POSIX上,shell = False(默认值):在本例中为Popen类   使用os.execvp()来执行子程序。 args应该正常   是一个序列。字符串将被视为带有字符串的序列   作为唯一的项目(要执行的程序)。

     

在POSIX上,shell = True:如果args是一个字符串,则指定   命令字符串通过shell执行。如果args是一个序列,   第一项指定命令字符串和任何其他项   将被视为额外的shell参数。

'为什么'问题倾向于被关闭,因为他们很少有明确的答案,或者他们涉及意见或历史。

我建议研究shell=False代码。我看到很多调用:

subprocess.py

它的初始是:

Popen(*popenargs, **kwargs)

作为关键字arg,def __init__(self, args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=()): 必须有一些默认值;为什么不是假的?

我怀疑在shell情况下它会将整个字符串传递给一些调用shell的代码。在无shell的情况下,它必须通过一个列表。但我们必须找到该代码。

有两种调用子进程的方法,一种用于POSIX,另一种用于Windows。在POSIX的情况下,它似乎转换字符串列表,无论shell是否为True它可能比那更细微,但这是相关的代码:

shell

在windows shell的情况下,args字符串与 """Execute program (POSIX version)""" if isinstance(args, (str, bytes)): args = [args] else: args = list(args) if shell: args = ["/bin/sh", "-c"] + args if executable: args[0] = executable .... self.pid = _posixsubprocess.fork_exec( args, executable_list,... info:

组合在一起
cmd