Выполните команду BASH в Python в том же процессе

Мне нужно выполнить команду . /home/db2v95/sqllib/db2profile, прежде чем я смогу import ibm_db_dbi в Python 2.6.

Выполнение его до того, как я войду в Python, работает:

baldurb@gigur:~$ . /home/db2v95/sqllib/db2profile
baldurb@gigur:~$ python
Python 2.6.4 (r264:75706, Dec  7 2009, 18:45:15) 
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ibm_db_dbi
>>> 

но выполнение его в Python с использованием os.system(". /home/db2v95/sqllib/db2profile") или subprocess.Popen([". /home/db2v95/sqllib/db2profile"]) приводит к ошибке. Что я делаю не так?

Изменить: я получаю сообщение об ошибке:

> Traceback (most recent call last):  
> File "<file>.py", line 8, in
> <module>
>     subprocess.Popen([". /home/db2v95/sqllib/db2profile"])  
> File
> "/usr/lib/python2.6/subprocess.py",
> line 621, in __init__
>     errread, errwrite)   File "/usr/lib/python2.6/subprocess.py",
> line 1126, in _execute_child
>     raise child_exception OSError: [Errno 2] No such file or directory

person Iceland_jack    schedule 18.05.2010    source источник
comment
Полное предположение, но похоже, что скрипт на самом деле устанавливает некоторые вещи в среде, которые, вероятно, не будут работать при выполнении подпроцесса.   -  person abyx    schedule 18.05.2010
comment
@abyx: но это не имеет отношения к данной проблеме, даже если это правда   -  person SilentGhost    schedule 18.05.2010


Ответы (4)


Вы звоните '.' команда оболочки. Эта команда означает «выполнить этот файл оболочки в текущем процессе». Вы не можете выполнить файл оболочки в процессе Python, поскольку Python не является интерпретатором сценария оболочки.

/home/b2v95/sqllib/db2profile, вероятно, устанавливает некоторые переменные среды оболочки. Если вы прочитаете его с помощью функции system(), то переменные будут изменены только в запущенной оболочке и не будут видны в процессе, вызывающем эту оболочку (ваш скрипт).

Вы можете загрузить этот файл только перед запуском вашего скрипта Python — вы можете создать скрипт-оболочку, который сделает . /home/b2v95/sqllib/db2profile и выполнит ваш скрипт Python.

Другой способ — посмотреть, что содержит db2profile. Если это всего NAME=value строк, вы можете проанализировать их в своем скрипте Python и обновить os.environ с помощью полученных данных. Если скрипт делает что-то большее (например, вызывает что-то еще для получения значений), вы можете переопределить весь скрипт на Python.

Обновление Идея: прочитать скрипт в python, передать его (используя Popen) в оболочку, после того как скрипт напишет команду env в ту же оболочку и прочитает вывод. Таким образом вы получите все переменные, определенные в оболочке. Теперь вы можете прочитать переменные.

Что-то вроде этого:

shell = subprocess.Popen(["sh"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
script = open("/home/db2v95/sqllib/db2profile", "r").read()
shell.stdin.write(script + "\n")
shell.stdin.write("env\n")
shell.stdin.close()
for line in shell.stdout:
    name, value = line.strip().split("=", 1)
    os.environ[name] = value
person Jacek Konieczny    schedule 18.05.2010
comment
Ах, хороший момент - db2profile действительно устанавливает переменные среды оболочки. К сожалению, я не могу вызвать скрипт python с помощью оболочки-оболочки (из-за характера проекта), файл db2profile длинный и включает в себя несколько умеренно сложных функций и (как вы уже догадались) переменные окружения. Как мне запустить весь файл в Python? - person Iceland_jack; 18.05.2010
comment
т.е. можно ли запустить сценарий BASH с большим количеством назначений, переменных среды и функций в Python? Или мне придется переписывать весь код на Python? - person Iceland_jack; 18.05.2010
comment
У меня появилась идея, как это можно сделать: смотрите обновление к моему посту. - person Jacek Konieczny; 18.05.2010
comment
Странно... выводит: Traceback (последний последний вызов): Файл ‹file›.py, строка 14, в ‹module› shell = subprocess.Popen([sh], stdin=subprocess.pipe, stdout=subprocess.pipe ) AttributeError: объект «модуль» не имеет атрибута «труба» - person Iceland_jack; 18.05.2010
comment
Это была моя ошибка (константа называется «PIPE», а не «pipe»), уже исправленная. - person Jacek Konieczny; 18.05.2010
comment
Если сценарий нужно выполнить только для установки переменных среды, вы можете попробовать запустить его в подоболочке и выполнить «env» в конце, чтобы вывести настройки среды. Прочитайте этот вывод в родительском процессе Python, проанализируйте и установите sys.env из этих настроек. - person Steven D. Majewski; 18.05.2010

вам нужно сделать:

subprocess.Popen(['.', '/home/db2v95/sqllib/db2profile'], shell=True)
person SilentGhost    schedule 18.05.2010
comment
Это может «работать» (не вызывать никаких исключений), но, скорее всего, не сделает того, что ожидалось. Поскольку файл является «источником», он, вероятно, устанавливает некоторые переменные среды. Эти переменные будут установлены только в оболочке, запущенной Popen, и не будут видны при вызове скрипта Python. - person Jacek Konieczny; 18.05.2010
comment
Это приводит к следующему: Traceback (последний последний вызов): Файл gagnagrunnur.py, строка 14, в ‹module› import ibm_db_dbi Файл /usr/local/lib/python2.6/dist-packages/ibm_db_dbi.py, строка 26, в ‹module› import ibm_db ImportError: libdb2.so.1: невозможно открыть общий объектный файл: нет такого файла или каталога Я хочу подчеркнуть, что это работало с использованием командной строки. - person Iceland_jack; 18.05.2010
comment
@baldur: вы ждете завершения процесса? - person SilentGhost; 18.05.2010

Не знаете, с какой ОС вы работаете и какую версию DB2 используете. Более новые версии (по крайней мере 9.5 и выше, не уверен насчет 9.0 или 9.1) работают, задав для db2clp значение **$$**. Поскольку DB2 обычно представляет собой LUW, она может работать и под linux/unix. Однако в AIX мне нужно запустить сценарий профиля, чтобы подключиться к нужному экземпляру БД. Не слишком много проверял, что делает этот скрипт.

person Peter Schuetze    schedule 27.05.2010

Возможно, os.popen — это то, что вы ищете (а еще лучше — один из popen[2-4] вариантов)? Пример:

import os
p = os.popen(". /home/b2v95/sqllib/db2profile")
p.close() # this will wait for the command to finish
import ibm_db_dbi

Изменить: я вижу, что ваша ошибка говорит No such file or directory. Попробуйте запустить его без точки, например:

os.popen("/home/b2v95/sqllib/db2profile")

Если это не сработает, возможно, это связано с вашей средой. Может быть, вы используете Python в тюрьме / chroot?

person Felix    schedule 18.05.2010
comment
О черт. Не увидел большого красного предупреждения. Прости за это. - person Felix; 18.05.2010
comment
Не только устарело — никогда не предназначалось для использования таким образом (чтобы открыть канал и игнорировать вывод). Если вы просто хотите запустить команду оболочки без связи с ней, используйте os.system() или subprocess.call(), а не os.popen(). - person Jacek Konieczny; 19.05.2010