its*_*_me 99 bash command-history
首先,这不是 SE 上任何现有线程的重复。我已经阅读了关于更好的 bash 历史的这两个线程(第 1 个,第 2 个),但没有一个答案有效 - 顺便说一下,我在 Fedora 15 上。
我.bashrc在用户目录(/home/aahan/)中的文件中添加了以下内容,它不起作用。有人有线索吗?
HISTCONTROL=ignoredups:erasedups # no duplicate entries
HISTSIZE=1000 # custom history size
HISTFILESIZE=100000 # custom history file size
shopt -s histappend # append to history, don't overwrite it
PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND" # Save and reload the history after each command finishes
Run Code Online (Sandbox Code Playgroud)
好的,这就是我想要的 bash 历史记录(优先级):
roz*_*acz 139
这实际上是一个非常有趣的行为,我承认我在开始时大大低估了这个问题。但首先是事实:
可以通过多种方式实现该功能,但每种方式的工作方式略有不同。请注意,在每种情况下,要将历史“传输”到另一个终端(更新),必须按下Enter终端,他/她要在其中检索历史。
选项1:
shopt -s histappend
HISTCONTROL=ignoredups
PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"
Run Code Online (Sandbox Code Playgroud)
这有两个缺点:
选项2:
HISTCONTROL=ignoredups
PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"
Run Code Online (Sandbox Code Playgroud)
(是的,不需要shopt -s histappend,是的,它必须 history -c在中间PROMPT_COMMAND)这个版本也有两个重要的缺点:
history命令可能会给出错误输出 - 见下文。[编辑] “而获胜者是……”
选项3:
HISTCONTROL=ignoredups:erasedups
shopt -s histappend
PROMPT_COMMAND="history -n; history -w; history -c; history -r; $PROMPT_COMMAND"
Run Code Online (Sandbox Code Playgroud)
这就是它得到的。使两者和共同历史记录同时工作是唯一的选择erasedups。
这可能是您所有问题的最终解决方案,Aahan。
正如我所提到的,上述每种解决方案的工作方式都不同。但对设置如何工作的最误导性解释来自分析historycommand的输出。在许多情况下,该命令可能会给出错误的输出。为什么?因为它在! 中包含的其他命令序列之前执行。historyPROMPT_COMMAND但是,当使用第二个或第三个选项时,可以监视.bash_history内容的变化(watch -n1 "tail -n20 .bash_history"例如使用)并查看真实的历史记录。
这一切都在于工作方式erasedups。正如 bash 手册所述, “(...)erasedups导致在保存该行之前从历史列表中删除与当前行匹配的所有先前行”。因此,这是真正的OP想要的东西(不只是,正如我以前认为,有没有出现重复序列)。这就是为什么每个history -.命令必须或不能在PROMPT_COMMAND:
history -n 必须在那里之前history -w读取.bash_history从任何其他终端保存的命令,
history -w 必须在那里以便在 bash 检查命令是否重复后将新历史记录保存到文件中,
history -a 不能放在那里而不是history -w,因为它会将任何新命令添加到文件中,无论它是否被检查为重复项。
history -c也是需要的,因为它可以防止在每个命令之后破坏历史缓冲区,
最后,history -r被需要从文件恢复历史缓冲器,从而最终使整个终端会话共享历史。
请注意,此解决方案会将来自其他终端的所有历史记录放在当前终端中输入的最新命令之前,从而弄乱历史记录顺序。它也不会删除历史文件中已有的重复行,除非您再次输入该命令。
在您的提示命令中,您正在使用-c开关。来自man bash:
-c 通过删除所有条目来清除历史列表
要与所有打开的终端共享您的历史记录,您可以使用-n:
-n 将尚未从历史文件中读取的历史行读入当前历史列表。这些是自当前 bash 会话开始以来附加到历史文件的行。
默认大小也在手册中:
HISTSIZE 命令历史记录中要记住的命令数(参见下面的 HISTORY)。默认值为 500。
保存多行命令:
该cmdhist shell选项,如果已启用,导致shell尝试保存多行命令的每一行中相同的历史条目,将分号在必要时维护语法的正确性。该lithist外壳选项使得shell保存嵌入的新行而不是分号的命令。
此外,您不应该在 HIST* 命令前面加上export- 它们是仅限 bash 的变量而不是环境变量:HISTCONTROL=ignoredups:erasedups就足够了。
小智 8
这就是我想出来的,到目前为止我很满意……
alias hfix='history -n && history | sort -k2 -k1nr | uniq -f1 | sort -n | cut -c8- > ~/.tmp$$ && history -c && history -r ~/.tmp$$ && history -w && rm ~/.tmp$$'
HISTCONTROL=ignorespace
shopt -s histappend
shopt -s extglob
HISTSIZE=1000
HISTFILESIZE=2000
export HISTIGNORE="!(+(*\ *))"
PROMPT_COMMAND="hfix; $PROMPT_COMMAND"
Run Code Online (Sandbox Code Playgroud)
笔记:
HISTIGNORE忽略所有没有参数的命令。某些人可能不希望这样做,可以将其排除在外。将@rozcietrzewiacz 的选项 3 与退出陷阱结合使用将使终端能够维护自己的独立历史会话,这些会话在关闭时会收敛。它甚至似乎适用于共享远程主目录的不同机器上的多个会话。
export HISTSIZE=5000
export HISTFILESIZE=5000
export HISTCONTROL=ignorespace:erasedups
shopt -s histappend
function historymerge {
history -n; history -w; history -c; history -r;
}
trap historymerge EXIT
PROMPT_COMMAND="history -a; $PROMPT_COMMAND"
Run Code Online (Sandbox Code Playgroud)
该historymerge函数从历史文件中加载会话外行,将它们与会话历史结合起来,用重复数据删除写出一个新的历史文件(从而压缩任何先前附加的重复行),并重新加载历史。
保持history -a提示可以最大限度地减少丢失历史的可能性,因为它会更新历史文件而不会对每个命令进行重复数据删除。
最后,陷阱historymerge在会话关闭时触发,以获取最新的干净历史文件,最近关闭的会话的命令冒泡到文件末尾(我认为)。
这样,从启动开始,每个终端会话都将拥有自己独立的历史记录。我发现这更有用,因为我倾向于为不同的任务打开不同的终端(因此我想在每个终端中重复不同的命令)。它也比理解多个终端不断尝试以分布式方式重新同步它们的有序历史要简单得多(尽管您仍然可以故意使用historymerge带有选择会话或所有会话功能)。
请注意,您希望您的大小限制足够大,以容纳所需的历史长度加上所有并发活动会话可能添加的非重复数据行的数量。5000 对我来说已经足够了,这主要是因为广泛使用HISTIGNORE来过滤掉垃圾的低价值命令。