为什么Windows上的sh无法正常使用Python的子进程调用?

以下代码显示hi

import subprocess
subprocess.call(['sh','-c',' "$@" ','-','echo','hi'])

但是,在本机Windows Python上,对代码进行了一些修改:

import subprocess
subprocess.call(['sh','"$@"','hi'])

产生以下错误:

sh: -c: line 0: unexpected EOF while looking for matching `"'
sh: -c: line 1: syntax error: unexpected end of file

这是为什么?

huazhua88225 回答:为什么Windows上的sh无法正常使用Python的子进程调用?

这似乎是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

大家都在问