继https://www.baeldung.com/linux/history-remove-avoid-duplicates之后,我添加了
clean_history() {
awk '!a[$0]++' $HOME/.bash_history > $HOME/.bash_history.tmp && mv $HOME/.bash_history.tmp $HOME/.bash_history
}
trap clean_history DEBUG # execute after every command
添加到我的 ~/.bashrc 文件中,以确保在执行每个命令后,删除重复的条目。这对我来说很重要,因为 kile(KDE LaTeX 编辑器)在历史记录中留下了大量“clear”和“cd ...”命令,这实际上会破坏单个 LaTeX 编写会话中的历史记录。而且我还没有找到任何方法可以阻止 kile 这样做。
无论如何……上面的代码行有效地删除了命令的所有后续条目,并将第一个条目保留在历史记录中。但是,我希望最后一个条目保留在历史记录中,并删除所有先前的条目。如何做到这一点?
顺便说一句:Kile 无视
HISTCONTROL=ignoredups:erasedups
因此使用这种方法似乎不是一个选择。
如果我们能够一起阻止凯尔写入历史,我也会很高兴。
非重复:
- 删除文本文件中的重复条目将保留文件中的第一个条目
- 那么如何删除文本文件中的重复行并获取删除的行数?
- 如何停止 Bash 追加历史记录
HISTCONTROL
您可以反转文件,处理它,然后将其反转回来。大多数系统都有
tail -r
GNUtac
(或其 busybox 或 toybox 克隆)来实现这一点:我们维护两个关联数组。
line[i]
给出行号的内容i
。当我们扫描输入时,lnum[str]
给出包含的最新行号str
。在每个步骤中,我们首先
line[]
通过在反向索引中查找行号来从数组中删除当前看到的行lnum
。然后,我们将当前行输入到数组中line
,并将当前行号更新lnum
为该行的最近出现。因此,如果当前行之前出现过,则会将其从数组中删除line
并由新条目取代。然后最后我们只需遍历行号并打印
line[i]
,前提是它尚未被删除。虽然该
tac
方法awk
大大简化了代码,但命令的可移植性较差,并且增加了额外的传递。该解决方案仍然会根据看到的行(尽管只有一行)构建关联表。注意:我们希望在
END
块中只执行for (n in line) print line[n]
,但 Awk 不保证关联数组索引的顺序。我认为这在 GNU Awk 中可以工作,但不可移植。您可以
kile
通过以 方式调用它来防止污染您的历史记录unset HISTFILE;HISTSIZE=0 kile
。另外,请参阅我的 AskUbuntu 回答: https://askubuntu.com/questions/80371/bash-history-handling-with-multiple-terminals/80882#80882
我不会按照书面形式回答问题,而是会提出解决根本问题的建议。
首先,如果您还没有这样做,请针对 Kile 提交错误报告;似乎至少应该有一个选项让 Kile 关闭 shell 历史记录。(当然,由于它可能无法依赖特定的 shell,这可能有点复杂,但例如运行特定的用户脚本仍然是一种解决方案,即使它需要更多的用户努力。)
其次...由于我们已经在谈论摆弄
.bashrc
(我假设是由 Kile 运行的),更好的解决方案是教它.bashrc
检测 shell 是否由 Kile 运行,并在这种情况下禁用历史记录:这将从 shell 的 PID (
$$
) 开始遍历进程树直到 pid 1,检查命令名称(##*/
删除可能存在也可能不存在的前导路径)是否与某个指定名称(在本例中为kile
)匹配。Kile 很可能是其正在运行的 shell 的父进程。(有多种方法可以与生成进程分离,但 Kile 不太可能这样做。至少 Konsole 不会这样做。)这也可能是矫枉过正;但
ps --no-headers -o cmd $(ps --no-headers -o ppid $$)
可能就足够了。无论如何,目标很简单;检测 bash 的父级/祖先是否是kile
,并据此“做某事”。我猜“某事”是set -o history
。