I'm trying to write a python script that will start mongod, create a database (or open a database I've already made), add some information, and then shut down mongod.
#!/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()
This code works, but reading the python docs, they say using shell=True in subprocess is a bad idea. I'm pretty novice with this stuff, and I don't really understand what the shell=True flag is doing, but I understand that having access to the shell when the input is variable is bad. The problem is, when I try to run this removing the shell=True argument, I get the following error:
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
Not sure if it matters, but in both the working case and failing case, I'm running this with create_mongo_database('test5_database', '~/computation/db') at the end of the script in sublime text3.
So my questions are - is using shell=True dangerous in this case? Why won't the program run if I don't do shell=True?
EDIT: Given Dano's and Charles Duffy's explanations, I've now changed the command to:
mongod = subprocess.Popen(
["mongod", "--dbpath", path_to_database],
)
However, this still doesn't work if path_to_database contains ~/. In other words, /Users/myusername/path/to/db works, but ~/path/to/db does not. My initial question is well answered, and I can definitely make this work, not sure if this new wrinkle should be made a new question or not...
I actually disagree rather strongly with the existing answer (suggesting shlex.split()). That makes sense if you have a shell-quoted string passed in that may contain an unknown number of arguments -- but in this case, you know exactly how many arguments you want: You want three, never more or less, and you want to be certain that path_to_database becomes only one argument.
Thus, the appropriate thing to use (if one wants tilde-expansion behavior) is:
mongod = subprocess.Popen(['mongod', '--dbpath', os.path.expanduser(path_to_database)])
Otherwise, a path including spaces will be split into multiple arguments, and a path containing literal quotes (they're legal on UNIX) will have those quotes treated as escaping/syntax rather than data. Using shell=True would do both these things and more -- making shlex.split() with the default shell=False certainly safer -- but passing an explicit array is better still.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With