【发布时间】:2016-05-07 17:20:45
【问题描述】:
在 bash 中,我可以通过在命令前面放置一个空格来防止将命令保存到 bash 历史记录中。我不能在 ipython 中使用这种方法。我将如何在 ipython 中进行等效操作?
【问题讨论】:
在 bash 中,我可以通过在命令前面放置一个空格来防止将命令保存到 bash 历史记录中。我不能在 ipython 中使用这种方法。我将如何在 ipython 中进行等效操作?
【问题讨论】:
我自己在寻找解决方案,然后意识到我可以input 这个秘密。例如,我在使用 pygithub 时使用下面的方式来初始化 github API:
In [1]: gh = github.Github(base_url="https://api.github.com", login_or_token=input("token: "))
token: abcd
In [2]: %hist
gh = github.Github(base_url="https://api.github.com", login_or_token=input("token: "))
%hist
【讨论】:
过时说明:这是为IPython 4.0.1 编写的。 As of v5, IPython no longer uses readline.
没有库存方式,可以添加或解决。
IPython 中有两种历史:
readline 历史。它可用于特殊键/组合键(上/下、Ctrl-R 等)。仅将输入的行(使用<Enter>)存储在控制台上(或者,在pyreadline 中,也从剪贴板粘贴)。 IPython 依赖于 Python readline API 的本地实现,它没有“不添加”功能,通常会将每一行添加到历史记录中。
IPython 有一个工具可以缓解这种情况,IPython.core.interactiveshell.ReadlineNoRecord,它是一个上下文管理器,可以创建历史快照然后恢复它。从ipython 4.0.1 开始,它仅被%run 魔法使用,以避免将脚本交互输入添加到历史记录中。
IPython 历史。它保存在数据库和自动变量中。它包含完整的输入(readline 分别抓取每条<Enter>'ed 行用于多行)和输出。保存在HistoryManager.store_inputs()(用于输入)和HistoryManager.store_output()(用于输出)中实现,从InteractiveShell.run_cell 调用并由其store_history 参数控制。后者依次从TerminalInteractiveShell.interact 和store_history=True 调用。
有两种方法可以解决任一层的问题:
首先防止添加输入。这不能通过命令前缀的魔法来完成,只能通过作为单独命令运行并切换标志的魔法来完成。这是因为,如您所见,当前输入在魔法命令获得控制时已经存储。
pyreadline,添加是通过pyreadline.modes.basemode.BaseMode.add_history() 完成的。模式对象可通过get_ipython().readline.rl.mode 访问。run_cell 和 add_history 与检查相应对象中的标志的包装器和设置/切换它们的 custom magic command 应该可以解决问题。执行后立即从历史记录中自动删除证据输入/输出。这可以通过前缀魔法来完成。
HistoryManager 没有任何工具可以删除条目(无论是从数据库中还是从变量中)。唉,手动破解数据库/更换库存HistoryManager 是必要的。另请注意,该类有一个可选的缓存 HistoryManager.db_cache_size(默认禁用)。remove_history_item(index) 在 API 中。您需要知道输入中的行数。或者,如果您只需要它来输入密码,请考虑在屏幕上不回显密码的其他方式(因此不会使其成为控制台历史记录的一部分):
getpass.getpass()【讨论】:
%toggle,your_command,%toggle; 2)这意味着用它们周围的包装器替换这些函数;一个例子超出了答案的范围,任何具有相当专业知识的人都应该清楚。
我想我终于弄明白了。这种方法并没有真正“阻止” ipython 记录历史记录,而是实际上删除历史记录。但我认为这仍然是实现这一目标的好方法。
ipython 历史存储在$(ipython locate)/profile_default/history.sqlite 的sqlite 数据库 文件中。
数据库表History有四列:session、line、source和source_raw。 session 列表示当前会话的session_id,可以通过ipython 中的方法得到:get_ipython().history_manager.hisdb.get_last_session_id() in ipython。 line 列就是行号。
所以我要做的是在ipython环境中的数据库中删除这条记录:
1) 历史数据库对象可以在ipython 中使用get_ipython().history_manager.db 获取
hismgr = get_ipython().history_manager
2) 获取会话ID:
session_id = hismgr.get_last_session_id()
3) 删除带有line_id(假设这里是111)和session_id的历史记录行
hismgr.db.execute('DELETE FROM history WHERE line={0} and session={1}'.format(111, session_id))
4) In 和 Out Array List 也有点像历史,但它存储在内存中,所以它可以像变量一样被扫描或重写。
In[111]=Out[111]=''
“防止命令被保存到 ipython 历史”,是指删除数据库中该行的 history 记录,并重写 In 和 Out ipython 环境中的数组。我们可以将这四行合二为一,一次性完成这项工作。 这是一个示例,如果我们要删除第 128 行:
In [127]: history -l 3 -n
124: history -l 3 -n
125: hismgr = get_ipython().history_manager; session_id = hismgr.get_last_session_id();hismgr.db.execute('DELETE FROM history WHERE line={0} and session={1}'.format(123, session_id))
126: history -l 3 -n
In [128]: passwd='123456'
In [129]: hismgr = get_ipython().history_manager; session_id = hismgr.get_last_session_id();hismgr.db.execute('DELETE FROM history WHERE line={0} and session={1}'.format(128, session_id));In[128]=Out[128]='';
Out[129]: <sqlite3.Cursor at 0x7f8dce3dae30>
In [130]: history -l 3 -n
126: history -l 3 -n
127: history -l 3 -n
129: hismgr = get_ipython().history_manager; session_id = hismgr.get_last_session_id();hismgr.db.execute('DELETE FROM history WHERE line={0} and session={1}'.format(128, session_id));In[128]=Out[128]='';
历史线 128 不见了。
这是我浏览的一些文件
【讨论】: