scp с подпроцессом Python3 [дубликат]

Для Mac,

  1. войдите на сервер mysql.
  2. выполните следующую команду:
     SHOW VARIABLES LIKE "%version%";
    
19
задан Ben Hoyt 10 August 2009 в 05:39
поделиться

3 ответа

Фактически в Windows он использует cmd.exe, когда shell=True - он добавляет cmd.exe /c (он фактически ищет переменную среды COMSPEC, но по умолчанию имеет значение cmd.exe, если нет) аргументам оболочки. (В Windows 95/98 он использует промежуточную программу w9xpopen для фактической запуска команды).

Таким образом, странная реализация на самом деле является UNIX, которая делает следующее (где каждое пространство разделяет другой аргумент):

/bin/sh -c gcc --version

Похоже, правильная реализация (по крайней мере, в Linux) была бы:

/bin/sh -c "gcc --version" gcc --version

Поскольку это установило бы командную строку из котируемых параметров , и успешно передайте другие параметры.

Из раздела sh man-страницы для -c:

Read commands from the command_string operand instead of from the standard input. Special parameter 0 will be set from the command_name operand and the positional parameters ($1, $2, etc.) set from the remaining argument operands.

Этот патч довольно просто выполняет трюк:

--- subprocess.py.orig  2009-04-19 04:43:42.000000000 +0200
+++ subprocess.py       2009-08-10 13:08:48.000000000 +0200
@@ -990,7 +990,7 @@
                 args = list(args)

             if shell:
-                args = ["/bin/sh", "-c"] + args
+                args = ["/bin/sh", "-c"] + [" ".join(args)] + args

             if executable is None:
                 executable = args[0]
14
ответ дан David Fraser 20 August 2018 в 22:21
поделиться
  • 1
    Это здорово, спасибо Дэвиду. Я согласен с правильной реализацией, и ваш патч выглядит хорошо. Вы находитесь в лучшем положении, чем я, чтобы представить отчет об ошибке Python - другими словами, вы сделали это раньше или я буду изучать его? – Ben Hoyt 10 August 2009 в 22:59
  • 2
    Добавлено bugs.python.org/issue6689 - было бы хорошо, если бы вы могли следить за ним, комментировать там и т. Д. – David Fraser 12 August 2009 в 09:35
  • 3
    Благодаря! Я добавил себя в любопытный список. – Ben Hoyt 13 August 2009 в 00:20
  • 4
    Для справки патч был отклонен. Может быть, стоит подумать, нужно ли вместо этого внести исправления в документацию - я оставлю это до заинтересованной стороны – David Fraser 21 July 2010 в 18:49

Из источника subprocess.py:

В UNIX с оболочкой = True: если args - это строка, она указывает строку команд, выполняемую через оболочку. Если args - это последовательность, первый элемент указывает командную строку, а любые дополнительные элементы будут рассматриваться как дополнительные аргументы оболочки.

В Windows: класс Popen использует CreateProcess () для выполнения дочерней программы, которая работает на строках. Если args - это последовательность, она будет преобразована в строку, используя метод list2cmdline. Обратите внимание, что не все приложения MS Windows интерпретируют командную строку так же: List2cmdline предназначена для приложений, использующих те же правила, что и среда выполнения MS C.

Это не отвечает на вопрос, просто объясняет, что вы видите ожидаемое поведение.

Вероятно, что «почему» в UNIX-подобных системах аргументы команды фактически передаются приложениям (с использованием семейства вызовов exec*) в качестве массив строк. Другими словами, вызывающий процесс решает, что входит в аргумент командной строки EACH. Если вы говорите ему использовать оболочку, вызывающий процесс на самом деле получает возможность передать только один аргумент командной строки для выполняемой оболочки: всю командную строку, которую вы хотите исполнить, исполняемое имя и аргументы, как одна строка.

Но в Windows вся командная строка (согласно приведенной выше документации) передается в виде отдельной строки дочернему процессу. Если вы посмотрите на документацию API CreateProcess , вы заметите, что он ожидает, что все аргументы командной строки будут объединены вместе в большую строку (следовательно, вызов list2cmdline).

Плюс есть тот факт, что в UNIX-подобных системах на самом деле есть оболочка, которая может делать полезные вещи, поэтому я подозреваю, что другая причина разницы в том, что в Windows, shell=True ничего не делает, поэтому он работает так, как вы видите. Единственный способ заставить эти две системы действовать одинаково - это просто отказаться от всех аргументов командной строки, когда shell=True в Windows.

5
ответ дан Adam Batkin 20 August 2018 в 22:21
поделиться
  • 1
    В Windows тоже есть оболочка (обычно cmd.exe), но приведенный выше комментарий указывает на то, что Python фактически не использует его, когда shell = True (вместо этого он напрямую использует CreateProcess()). – Greg Hewgill 10 August 2009 в 06:02
  • 2
    Спасибо, как упоминал Грег, определенно есть оболочка на Windows (cmd.exe или одна в COMSPEC). И он используется Popen (хотя через CreateProcess) - см. Источник subprocess.py. Поэтому мне все же определенно кажется, что подпроцесс должен заставить их работать одинаково, чтобы избежать ошибок переносимости ... – Ben Hoyt 10 August 2009 в 06:11
  • 3

Причина поведения UNIX shell=True связана с цитированием. Когда мы пишем команду оболочки, она будет разбита на пробелы, поэтому мы должны привести некоторые аргументы:

cp "My File" "New Location"

Это приводит к проблемам, когда наши аргументы содержат кавычки, которые требует ускорения:

grep -r "\"hello\"" .

Иногда мы можем получить ужасные ситуации , где \ тоже нужно сбежать!

Конечно, реальная проблема в том, что мы пытаемся использовать строку one для указания строк multiple . При вызове системных команд большинство языков программирования избегают этого, позволяя нам в первую очередь отправлять несколько строк, следовательно:

Popen(['cp', 'My File', 'New Location'])
Popen(['grep', '-r', '"hello"'])

Иногда бывает неплохо запускать «необработанные» команды оболочки; например, если мы скопируем что-то из сценария оболочки или веб-сайта, и мы не хотим конвертировать все ужасное экранирование вручную. Вот почему существует опция shell=True:

Popen(['cp "My File" "New Location"'], shell=True)
Popen(['grep -r "\"hello\"" .'], shell=True)

Я не знаком с Windows, поэтому я не знаю, как и почему она ведет себя по-другому.

0
ответ дан Warbo 20 August 2018 в 22:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: