Это, похоже, удивительно давняя ошибка в MSYS2 (вероятно, от Cygwin), вызванная особенностью Windows цитированием правил . Что происходит, так это то, что MSYS2 ожидает, что
subprocess.list2cmdline(['sh', '-c', '"$@"' , '-', 'echo', 'hi'])
переведет в
sh -c "\"$@\"" - echo hi
, но на самом деле выдает следующее:
sh -c \"$@\" - echo hi
Трудно понять, почемудо тех пор, пока вы не поймете, что MSYS2 считает, что правила цитирования в командной строке Windows таковы, что обратные слеши обрабатываются как литералы вне двойных кавычек.
В итоге получается, что \"$@\"
получаетинтерпретируется как одиночная обратная косая черта, за которой следует строка $@\"
в кавычках, конечная кавычка которой отсутствует . Если бы мы добавили заключительную кавычку, она бы фактически выглядела как \"$@\""
, что кажется несбалансированным, но на самом деле сбалансировано с MSYS2. (!)
Однако, когда аргумент содержит пробел, все это наивно цитируется, случайно маскируя проблему.
Почему он интерпретирует вещи таким образом? Вероятно, это связано с документацией, в которой написано :
CommandLineToArgvW
имеет специальную интерпретацию символов обратной косой черты, когда за ними следует символ кавычки ("
). Эта интерпретация предполагает, что любой предыдущий аргумент является допустимым путем к файловой системе, иначе он может вести себя непредсказуемо.
Эта специальная интерпретация управляет режимом "в кавычках" , отслеживаемым анализатором.
Довольно просто и соблазнительно неправильно это понять и думать, что обратные слэши теряют свое особое значение, когда анализатор не в режиме «в кавычках», и это то, что говорит анализатор MSYS2. Однако, если вы внимательно прочитаете следующие два предложения, это объясняет, что именно означает «in-quotes» :
Когда этот режим отключен, пробел завершает текущий аргумент. Когда включено, пробел добавляется к аргументу, как и все другие символы.
То есть 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', '-c', '"$@"', '-', 'echo', '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', '-c', '"$@"', '-', 'echo', 'hi'])
Это не должно влиять на любые программы с корректным поведением, потому что есть несколько способов заключать в кавычки, но это должно решить проблему с MSYS2.