Проблема вызова Bash из Python - PullRequest
3 голосов
/ 22 марта 2012

Я пытаюсь использовать python, чтобы помочь автоматизировать инкрементную функцию сборки в системе сборки Android.Как правило, из заданного каталога я выполняю следующую команду для построения того, что находится в этом каталоге и подкаталогах:

mm -j8

Это аналог команды "make", только она является инкрементной сборкой и определяетсякак функция в файле bash с именем envsetup.sh.Что делает это не важно, просто знайте, что это функция, определенная в скрипте bash где-то в файловой системе.Чтобы выполнить это, я также могу сделать:

bash -c ". /path/to/envsetup.sh; mm -j8"

Этот метод вызова будет важен при вызове функции из python.Я следовал решению здесь , которое показывает, как вызывать функцию в скрипте bash из python.Я использовал этот метод в простом сценарии, который, теоретически, должен просто выплевывать STDOUT и STDERR от выполнения команды:

import subprocess

command = ['bash', '-c', '. /path/to/envsetup.sh; mm -j8']
(stdout, stderr) = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()

print 'stdout: ' + stdout
print 'stderr: ' + stderr

Однако вызов Popen никогда не возвращается.Что я делаю неправильно, что позволило бы bash правильно выполнить команду, но Python зависает при выполнении команды?

1 Ответ

3 голосов
/ 22 марта 2012

ТЛ;dr:

Ваша проблема - использование shell=True.Установите для него значение shell=False, и оно будет работать.

Если эта опция установлена, python будет просто запускать первый элемент массива command, то есть bash как сценарий оболочки.Поэтому в настоящее время python запускает собственную оболочку для запуска вашей команды (bash).Он запустит bash без аргументов, а затем bash будет ожидать ввода, блокируя ваш скрипт на python.

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

>>> import subprocess
>>> subprocess.Popen(['bash', 'whatever'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()

Вот как выглядит дерево процессов, когда я запускаювыше:

  \_ python
      \_ /bin/sh -c bash whatever
          \_ bash

Фактически передается whatever, но это параметр для sh, а не параметр для внутреннего bash, поэтому выполняемая команда эффективна ['/bin/sh', '-c', 'bash', 'whatever'], что весьма отличается от ['/bin/sh', '-c', 'bash whatever']

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...