Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opening Mongod within python, how to avoid `shell=True`

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...

like image 539
kevbonham Avatar asked Jun 02 '26 18:06

kevbonham


1 Answers

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.

like image 73
Charles Duffy Avatar answered Jun 05 '26 06:06

Charles Duffy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!