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