这似乎是Windows的idiosyncratic quoting rules导致的MSYS2(可能来自Cygwin)中的一个令人惊讶的长期错误。
MSYS2期望发生什么事
subprocess.list2cmdline(['sh','-c','"$@"','-','echo','hi'])
翻译为
sh -c "\"$@\"" - echo hi
但实际上它会产生以下内容:
sh -c \"$@\" - echo hi
很难理解为什么会这样,直到您意识到MSYS2认为Windows命令行引用规则使得反斜杠在双引号之外被视为 literal 。
因此,最终发生的情况是\"$@\"
被解释为单个文字反斜杠,后跟带引号的字符串$@\"
,其结尾引号为 missing 。如果我们添加结尾引号,则实际上看起来像\"$@\""
,它似乎不平衡,但实际上与MSYS2平衡。 (!)
但是,当参数包含空格时,整个内容都会被天真地引用,从而无意中掩盖了问题。
为什么它用这种方式解释事物?可能是因为文档says:
CommandLineToArgvW
对反斜杠字符加引号字符("
的特殊解释。这种解释假定任何前面的参数是有效的文件系统路径,否则可能表现为不可预测的。
此特殊解释控制解析器跟踪的“用引号引起来”模式。
很容易并容易误解这一点,并认为当解析器在“ in-quotes”模式下不是时,反斜杠将失去其特殊含义,这就是MSYS2解析器所说的。但是,如果您仔细阅读了下面的两个句子,它可以准确解释“引用内”模式的含义:
关闭此模式时,空格将终止当前参数。启用此选项后,空格会像其他所有字符一样添加到参数中。
就是 all 。反斜杠不要突然成为引号之外的逐字记录。他们仍然可以像在内部一样对引号进行转义,当然,规则甚至比内部要复杂得多。
您如何解决此问题?幸运的是,本机Windows Python允许将整个命令行作为单个字符串文字传递,因此您实际上可以使用辅助方法来解决此错误:
import subprocess
def list2cmdline(args): return ' '.join(map(
lambda a: a if a.lstrip().startswith('"') or '"' not in a else '"' + a + '"',map(lambda a: subprocess.list2cmdline([a]),args)))
subprocess.call(list2cmdline(['sh','hi']))
或者,您可以直接对其进行猴子补丁:
import subprocess
subprocess.list2cmdline = (lambda old: lambda args: ' '.join(map(
lambda a: a if a.lstrip().startswith('"') or '"' not in a else '"' + a + '"',map(lambda a: old([a]),args))))(subprocess.list2cmdline)
subprocess.call(['sh','hi'])
这不应该影响任何行为正确的程序,因为有多种引用方式,但是应该可以解决MSYS2的问题。
本文链接:https://www.f2er.com/3168911.html