在python中打开Mongod,如何避免`shell=True`
我正在尝试编写一个python脚本,该脚本将启动mongod,创建一个数据库(或打开我已经创建的数据库),添加一些信息,然后关闭mongod在python中打开Mongod,如何避免`shell=True`,python,mongodb,shell,subprocess,Python,Mongodb,Shell,Subprocess,我正在尝试编写一个python脚本,该脚本将启动mongod,创建一个数据库(或打开我已经创建的数据库),添加一些信息,然后关闭mongod #!/usr/bin/env python from pymongo import MongoClient import subprocess def create_mongo_database(database_name, path_to_database): mongod = subprocess.Popen( "mongo
#!/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()
这段代码可以工作,但是阅读python文档时,他们说在子流程中使用shell=True
是个坏主意。我是这方面的新手,我不太明白shell=True
标志在做什么,但我知道当输入是变量时访问shell是不好的。问题是,当我尝试在删除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
但是,如果数据库的路径包含~/,这仍然不起作用。换句话说,
/Users/myusername/path/to/db
起作用,但~/path/to/db
不起作用。我最初的问题得到了很好的回答,我完全可以做到这一点,不确定这个新问题是否应该成为新问题……如果不使用shell=True
,则需要将命令拆分为各个参数。最简单的方法是:
Edit:Charles Duffy指出,在这种情况下,使用shlex.split
将无法正确处理所有可能的路径。最好只显式地传递带有shell=False
的数组。更多信息请参见他的答案
shell=True
命令告诉Python使用底层命令提示符(例如bash、sh等)执行命令。之所以认为shell=True
是危险的,是因为如果将用户定义的字符串传递到命令中,它们可能会生成一个执行任意代码的命令。因此,在您的示例中,如果用户提供了数据库的路径,想象一下他们是否传递了这个:“ls/”
。在shell中执行命令时,代码>字符被视为命令分隔符,除执行mongod
命令外,您还将执行ls/
。显然,这是非常糟糕的
如果改用shell=False
,则;ls/
字符将被视为mongod
命令的参数,而不是传递给shell,其中代码>具有特殊的含义
综上所述,如果path\u to_database
不是也永远不会由用户提供,那么使用shell=True
应该是安全的,但一般来说,只有在您确实需要的时候才使用它是一个好主意。我实际上非常不同意现有的答案(建议shlex.split()
)。如果传入了一个带shell引号的字符串,该字符串可能包含未知数量的参数,那么这是有意义的——但在本例中,您确切地知道需要多少个参数:您需要三个,而不是更多或更少,并且您要确保path\u to\u database
仅成为一个参数
因此,适当的使用方法(如果需要瓷砖扩展行为)是:
否则,包含空格的路径将被拆分为多个参数,而包含文字引号的路径(在UNIX上是合法的)将把这些引号视为转义/语法,而不是数据。使用shell=True
可以做这两件事,甚至更多——使用默认的shell=False使shlex.split()
更安全——但是传递一个显式数组更好。@CharlesDuffy是的,你是对的。关于shell=True
和shell=False
之间的区别,我会留下我的答案,但是在这种情况下,使用显式数组肯定比使用shlex.split
要好。我同意——这个解释很有用;编辑后,这是我的投票。@dano这非常清楚,谢谢你的解释!但有一个新的皱纹-请看我的编辑。不确定我是否应该提出一个新问题…@kevbonham用于处理“~”
。思考实验:如果您的数据库位于名为“/computation/$(rm-rf.)/db”
的目录中,会发生什么情况?我想我的硬盘上可能什么都没有了?那会很有趣…是的(最坏的情况,取决于细节)!但实际上,正是由shell=True
调用的shell实现了这种扩展;如果没有shell,那么名称将被视为一个文本文件名;我也适当地扩展了我的答案。糟了,我不能把两种解释都标记为回答。。。我想读这两本书(以及你的假设书)有助于我理解。有一个新的皱纹虽然-请看看我的编辑。
mongod = subprocess.Popen(
["mongod", "--dbpath", path_to_database],
)
mongod = subprocess.Popen(
shlex.split("mongod --dbpath {0}".format(os.path.expanduser(path_to_database)))
)
mongod = subprocess.Popen(['mongod', '--dbpath', os.path.expanduser(path_to_database)])