2015-04-10 1 views
2

Я пытаюсь написать скрипт python, который запустит mongod, создаст базу данных (или откройте базу данных, которую я уже сделал), добавьте некоторую информацию и затем выключите монгод.Открытие Mongod в python, как избежать `shell = True`

#!/usr/bin/env python 

from pymongo import MongoClient 
import subprocess 

def create_mongo_database(database_name, path_to_database): 
    mongod = subprocess.Popen(
     "mongod --dbpath {0}".format(path_to_database), 
     shell=True 
    ) 
    client = MongoClient() 
    db = client[database_name] 
    collection = db['test_collection'] 
    collection.insert_one({'something new':'some data'}) 
    mongod.terminate() 

Этот код работает, но читать питон документы, они говорят, что с помощью shell=True в подпроцессе является плохой идеей. Я довольно новичок в этом, и я действительно не понимаю, что делает флаг shell=True, но я понимаю, что доступ к оболочке, когда переменная ввода является плохим. Проблема заключается в том, когда я пытаюсь запустить это удаляя shell=True аргумент, я получаю следующее сообщение об ошибке:

Traceback (most recent call last): 
    File "/Users/KBLaptop/computation/kvasir/mongo_test2.py", line 23, in <module> 
    create_mongo_database('test5_database', '~/computation/db') 
    File "/Users/KBLaptop/computation/kvasir/mongo_test2.py", line 12, in create_mongo_database 
    "mongod --dbpath {0}".format(path_to_database), 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 709, in __init__ 
    errread, errwrite) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1326, in _execute_child 
    raise child_exception 
OSError: [Errno 2] No such file or directory 

Не уверен, если это имеет значение, но и в рабочем случае и неисправного случае, я бегу это с create_mongo_database('test5_database', '~/computation/db') в конце сценария в возвышенном тексте3.

Так что мои вопросы - это shell=True опасный в этом случае? Почему программа не запускается, если я не делаю shell=True?

EDIT: Учитывая объяснения Дано-х и Чарльз Даффи, Я теперь изменил команду:

mongod = subprocess.Popen(
    ["mongod", "--dbpath", path_to_database], 
) 

Однако, это все еще не работает, если path_to_database содержит ~/. Другими словами, /Users/myusername/path/to/db работает, но ~/path/to/db нет. Мой первоначальный вопрос хорошо ответил, и я могу определенно сделать эту работу, не уверен, что у этой новой морщинки должен быть задан новый вопрос или нет ...

+0

Мысленный эксперимент: что произойдет, если ваша база данных находится в каталоге с именем '/ computation/$ (rm -rf.)/Db?'? –

+0

Предполагаю, что на моем жестком диске ничего не осталось бы? Это было бы весело ... – kevbonham

+0

Yup (в худшем случае, в зависимости от деталей)! Но это оболочка, вызываемая 'shell = True', которая на самом деле чтит это расширение; если оболочки нет, тогда имя просто рассматривается как буквальное имя файла. –

ответ

3

Если вы не используете shell=True, вам необходимо разделить команду в его отдельные аргументы. Самый простой способ сделать это с shlex.split:

mongod = subprocess.Popen(
     shlex.split("mongod --dbpath {0}".format(os.path.expanduser(path_to_database))) 
    ) 

Edit: Чарльз Даффи указывает, что использование shlex.split в этом случае не будет вести себя должным образом для всех возможных путей. Лучше просто передать массив с shell=False. См. Его ответ для получения дополнительной информации.

Команда shell=True сообщает Python выполнить вашу команду, используя базовую командную строку (например, bash, sh и т. Д.). Причина, по которой shell=True считается опасной, заключается в том, что если вы передаете в команду пользовательскую строку, они могут создать команду, которая будет выполнять произвольный код. Итак, в вашем примере, если path_to_database предоставлен пользователем, представьте, передали ли они это: "; ls /". Когда вы выполняете команду в оболочке, символ ; обрабатывается как разделитель команд, и вы в конечном итоге выполняете ls / в дополнение к команде mongod. Очевидно, это очень плохо.

Если вы используете shell=False вместо этого, то ; ls / символов будут просто рассматриваться в качестве аргументов команды mongod, а не передаются в оболочку, где ; имеет особое значение.

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

+0

@CharlesDuffy Да, вы правы. Я оставлю свой ответ для объяснения различий между 'shell = True' и' shell = False', но использование явного массива определенно лучше, чем 'shlex.split' в этом случае. – dano

+0

Я согласен - объяснение полезно; как отредактировано, у меня есть мое преимущество. –

+0

@dano Это супер ясно, спасибо за объяснение! Но есть новая морщина - см. Мое редактирование. Не уверен, должен ли я задать новый вопрос или нет ... – kevbonham

4

Я действительно довольно не согласен с существующим ответом (предлагая shlex.split()). Это имеет смысл, если у вас есть переданная оболочка строка, в которой может содержаться неизвестное количество аргументов, но в этом случае вы знаете точно сколько аргументов вы хотите: вы хотите три, не более или менее, а вы хочу быть уверенным, что path_to_database становится только одним аргументом.

Таким образом, соответствующая вещь, чтобы использовать (если один хочет тильда-расширительный поведение) является:

mongod = subprocess.Popen(['mongod', '--dbpath', os.path.expanduser(path_to_database)]) 

В противном случае путь, включая пробелы будут разделены на несколько аргументов, и путь, содержащий буквальные цитаты (они 're legal on UNIX) будут иметь те кавычки, которые рассматриваются как экранирование/синтаксис, а не данные. Использование shell=True сделало бы обоим и многое другое - делая shlex.split() по умолчанию shell=False, безусловно, безопаснее, но передача явного массива еще лучше.

+0

Отстой, я не могу отметить оба объяснения как ответ ... Я думаю, что чтение обоих (и ваших гипотетических) помогло мне понять. Однако есть новая морщина - пожалуйста, взгляните на мое редактирование. – kevbonham

+0

Удивительный, это отлично работает! Благодаря! – kevbonham

Смежные вопросы