我正在寻找一种我在任何地方都没有见过的微妙的历史行为。
- 在终端会话期间,我希望每个命令(无论退出状态如何)都附加到内存历史记录中。
- 退出会话后,当内存中的历史记录写入磁盘时
~/.bash_history
,我想忽略失败的命令。
希望推理很清楚:在会话中,历史记录最常见的用途之一是重新尝试最后一个(失败的)命令,或者进行较小的编辑,或者在更改一些环境事实之后希望获得更好的结果。
但与此同时,我不希望我的长期历史充斥着错误的命令。
我见过这个帖子,它展示了如何(1)确定最后一个命令的退出状态,以及(2)如何通过索引删除历史条目。
而且我见过这个答案,它展示了如何trap
在会话结束时执行命令。
(我也研究过这个超级答案,这似乎涵盖了许多与历史操纵有关的怪癖。虽然我不确定它有多相关。)
我对如何实现我的目标有一个粗略的想法,但我对 bash 编程不太有经验,而且我在兑现它时遇到了困难。我的计划:
$TEMP/.bash_history_failures_IDENTIFIER
我为每个终端会话创建一个新文件,并替换IDENTIFIER
为某种特定于会话的值(PID?),以保证多个会话不会互相干扰number=$(history 1)
使用和的组合[ $exit_status -eq 127 ]
,我将每个错误命令的索引写入当前会话的失败文件- 使用
trap
钩子在退出时执行代码,我调用一个函数,该函数迭代此会话的失败文件中的索引,history -d $number
对每个条目执行操作 ~/.bash_history
最后,我让内存中历史记录的剩余部分(应该是所有且唯一成功的命令)根据我的HISTCONTROL
设置进行写入
我的建议可行吗?我在忽略什么?按升序从历史记录中删除项目时会遇到问题吗?为每个会话创建唯一文件的良好、稳定的方法是什么?
什么是“失败”命令?
我不希望长期历史记录包含用户错误:
- 不存在的命令
- 语法错误
我想保持命令正确,即使它们由于某些其他原因而无法执行(例如权限不足、输入路径不存在)。
我想到的两个例子是我经常忘记在单行代码中的哪里插入分号,如下所示:
for pkg in $(ls ./packages); do cp ./.eslintrc.yml ./packages/$pkg/; done
我不希望历史包含我将半决赛放在错误位置的条目。
另一种情况是,我通常需要多次尝试才能找到 的正确选项cut
,并且我的大多数错误是指定其参数时的语法错误。
如果我的长期 bash 历史能够忽略许多使工作命令正确的失败尝试,我会很高兴。我不关心包含例如碰巧没有结果的搜索的历史记录。
编辑以添加:
这哈斯特用于管理历史记录的 CLI 工具喜欢向 shell 配置文件中添加一些内容:
$ hstr --show-configuration
# HSTR configuration - add this to ~/.bashrc
alias hh=hstr # hh to be alias for hstr
export HSTR_CONFIG=hicolor # get more colors
shopt -s histappend # append new history items to .bash_history
export HISTCONTROL=ignorespace # leading space hides commands from history
export HISTFILESIZE=10000 # increase history file size (default is 500)
export HISTSIZE=${HISTFILESIZE} # increase history size (default is 500)
# ensure synchronization between bash memory and history file
export PROMPT_COMMAND="history -a; history -n; ${PROMPT_COMMAND}"
# if this is interactive shell, then bind hstr to Ctrl-r (for Vi mode check doc)
if [[ $- =~ .*i.* ]]; then bind '"\C-r": "\C-a hstr -- \C-j"'; fi
# if this is interactive shell, then bind 'kill last command' to Ctrl-x k
if [[ $- =~ .*i.* ]]; then bind '"\C-xk": "\C-a hstr -k \C-j"'; fi
我有预感,可以从 hstr 的代码库中蚕食一个解决方案。
答案1
尝试这个:
export PROMPT_COMMAND='LAST_COMMAND_EXIT=$? && history -a && test 127 -eq $LAST_COMMAND_EXIT && head -n -2 $HISTFILE >${HISTFILE}_temp && mv ${HISTFILE}_temp $HISTFILE'
如果退出状态为 127,只需删除 histfile 的最后两行(时间戳和命令)。对我来说效果很好,如果您在历史记录中没有时间戳,则应该head -n -1
使用-2
当然,您应该将此行添加到您的 .bashrc 以使其持久。
答案2
将其添加到您的 Bash 配置文件中:
nohist() { history -d $HISTCMD; }; trap nohist ERR
编辑:这更好,因为可以轻松检索错误行:
ce() { eval "$BASH_COMMAND; e='$BASH_COMMAND'"; false; }
if [[ $- == *i* ]]; then trap ce ERR; fi # capture error command
alias e='$e' # type e and then expand with ctrl-alt-e
此外,这将捕获每个输出以供重用(但它存在 echo 和 hist 的问题
save_output() {
exec 1>&3
{ [ -f /tmp/current ] && mv /tmp/current /tmp/last; }
exec > >(tee /tmp/current)
}
exec 3>&1
trap save_output DEBUG