2015-11-05 2 views
0

Я пытаюсь написать оболочку python для создания некоторого программного обеспечения. Мне нужно автоматизировать его строительство сотни раз с различными конфигурациями, что означает, что я не могу просто autogen.sh ; ./configure ; make ; make install. Некоторые из используемых конфигураций требуют запуска скрипта, который условно настраивает некоторые переменные среды. То, что я хочу, чтобы быть в состоянии сделать что-то вроде этого:Python скрипт, который запускает несколько команд оболочки и ждет результата

command = './autogen.sh' 
ret = subprocess.call(command.split()) 
if ret != 0: 
    sys.exit(ret) 

command = './script.sh ; ./configure <configure-flags>' 
ret = subprocess.call(command.split()) 
if ret != 0: 
    sys.exit(ret) 

command = 'make' 
ret = subprocess.call(command.split()) 
if ret != 0: 
    sys.exit(ret) 

command = 'make install' 
ret = subprocess.call(command.split()) 
if ret != 0): 
    sys.exit(ret) 

Проблема я бегу в том, что переменные окружения, установленные в script.sh не становятся сохранены для configure. Я видел частичное решение в Sending multiple commands to a bash shell which must share an environment, но это связано с промывкой команд stdin и опросом результата, который не будет работать, когда у вас действительно длинный makefile (мой занимает около 10-20 минут), и он также не дает вы возвращаете значение, которое мне нужно знать, если сборка была успешной или нет.

Кто-нибудь знает лучший способ сделать это?

ответ

0

Основная проблема заключается в том, что переменные окружения копируются только «вниз» (от родителя к дочернему), никогда «вверх» (от ребенка к родительскому). Ваш скрипт python является родительским. Он выполняет команду оболочки, которая, следовательно, является дочерней; оболочка запускает больше команд, которые являются дочерними элементами оболочки (и, следовательно, внуками процесса Python).

Чтобы переменные среды сохранялись, вам нужно каким-то образом импортировать их вверх. Именно так зависит от вас. Общий метод (используемый в сценариях оболочки, а также в Python) заключается в том, чтобы экспортер печатал значения, которые он хотел установить, а затем обработчик оболочки или Python считывал этот вывод и выполнял настройку. (. Я вижу, что это то, что после вас связного НОО)

Например, дочерний процесс может печатать:

CONFIG_PATH=/path/to/config/file 

(или же с export добавил), а затем внешняя оболочка будет просто eval это. Это подразумевает большое доверие: что, если дочерний процесс печатает rm -rf /? Можно применить правила (сопоставление регулярных выражений, например) к выходу перед его выполнением, или даже вручную (или автоматически), проанализировать его, но не выполнить результат до тех пор, пока не будет выполнен шаг проверки.

Другой способ - записать конфигурацию в файл и родительский прочитать файл. Это почти такая же техника, но с использованием файла для депо для обмена данными, вместо того, чтобы возиться с stdin и stdout. У него есть еще несколько проблем (имя файла и знание, когда его читать).

(Там, конечно, много сборки и/или тестовые структур, написанных на Python. Я не буду рекомендовать какие-то конкретные из них, как я не так много опыта работы с ними.)

+0

Я на самом деле не все, что придирчивый об окружающей среде сохраняется от одного 'вызова()' на другой. Я в порядке с вызовом сценария установки в каждом 'call()'. –

+0

"Что делать, если дочерний процесс печатает' rm -rf/'", что если дочерний процесс просто запускает 'rm -rf /' напрямую? –

+0

@thatotherguy: действительно. :-) Я думаю больше о более крупных системах, которые используют подпозиции, находящиеся в изоляции (разные UID, возможно, даже на другой виртуальной машине и т. Д.) С более узкими каналами связи. – torek

1

Если у вас есть скрипт, который устанавливает переменные, которые вы хотите получить после этого, вы должны указать его (аналогично тому, что другие языки называют «include»).

Вместо

command = './script.sh ; ./configure <configure-flags>' 
ret = subprocess.call(command.split()) 

вы можете сделать

command = ["bash", "-c", "source script.sh; ./configure"] 
subprocess.call(command) 
Смежные вопросы