不知道怎么搞的,新版 MongoDB 自带的 mongo shell 现在不支持 readline,而且使用一个极简到工作不正常的 linenoise。编译时加上 readline 也没用。虽然内建了简单的历史记录和补全,可是历史记录不能搜索,补全只能像 Vim 命令行默认的那样一个一个切换不能像 bash/zsh 那样全部列出来。这些还不是最令人郁闷的。最让我受不了的问题和十年前的 DOS 版 WPS 里遇到的差不多——当年的 WPS 里删汉字一次只删一半,现在的 mongo shell 里删汉字一次只删三分之一!而且光标定位是错的,按字节算的!
于是乎拿 Python 写了一个 shell。不愧是 Python,内置的东西真不错,不到100行就写好了。不过用到了自己另外的库函数,另外用到了自己的 colorless 程序来高亮显示查询结果。如果不想要 pygments 这个依赖的话,可以用 less 程序代替。以下贴个无高亮版的,高亮版的见 github。
#!/usr/bin/env python3
# vim:fileencoding=utf-8
import sys
import os
from pprint import pprint
import subprocess
from pymongo import Connection
import pymongo.cursor
# 这个模块位于 github 上的 winterpy 仓库的 pylib/cli.py
from cli import repl
import locale
locale.setlocale(locale.LC_ALL, '')
del locale
host = 'localhost'
port = 27017
db = 'test'
def displayfunc(value):
if isinstance(value, pymongo.cursor.Cursor):
p = subprocess.Popen(['less', '-RFX'], stdin=subprocess.PIPE,
universal_newlines=True)
pprint(list(value), stream=p.stdin)
p.stdin.close()
p.wait()
else:
pprint(value)
def main():
global db
conn = Connection(host=host, port=port)
db = conn[db]
v = globals().copy()
v.update(locals())
del v['repl'], v['argv'], v['main'], v['v'], v['host'], v['port']
del v['displayfunc'], v['subprocess']
del v['__name__'], v['__cached__'], v['__doc__'], v['__file__'], v['__package__']
sys.displayhook = displayfunc
repl(
v, os.path.expanduser('~/.mongo_history'),
banner = 'Python MongoDB console',
)
if __name__ == '__main__':
argv = sys.argv
if len(argv) == 2:
if '/' in argv[1]:
host, db = argv[1].split('/', 1)
if ':' in host:
host, port = host.split(':', 1)
elif len(argv) == 1:
pass
else:
sys.exit('argument error')
main()
