不知道怎么搞的,新版 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()