it-swarm.cn

Bash历史记录:“ ignoredups”和“ erasedups”设置与跨会话的通用历史记录冲突

首先,这不是SE上任何现有线程的重复。我已经阅读了有关更好的bash历史记录的这两个线程( 1st2nd ),但是没有一个答案有效--顺便说一下,我在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

好的,这就是我想要的bash历史记录(优先级):

  • 不存储重复项,删除任何现有的重复项
  • 立即与所有打开的终端共享历史
  • 总是附加历史记录,而不是覆盖它
  • 将多行命令存储为单个命令(默认情况下处于关闭状态)
  • 默认的历史记录大小和历史记录文件大小是多少?
92
its_me

这实际上是一种非常有趣的行为,我承认一开始我就大大低估了这个问题。但首先是事实:

1.什么有效

该功能可以通过多种方式实现,尽管每种方式的工作方式略有不同。请注意,在每种情况下,要将历史记录“传输”到另一终端(更新),必须按 Enter 在终端中,他/她想在其中检索历史记录。

  • 选项1:

    shopt -s histappend
    HISTCONTROL=ignoredups
    Prompt_COMMAND="history -a; history -n; $Prompt_COMMAND"
    

    这有两个缺点:

    1. 登录(打开终端)时,历史文件中的最后一条命令被两次读取到当前终端的历史缓冲区中。
    2. 不同终端的缓冲区不会与历史文件保持同步。
  • 选项2:

    HISTCONTROL=ignoredups
    Prompt_COMMAND="history -a; history -c; history -r; $Prompt_COMMAND"
    

    (是的,不需要shopt -s histappend,是的,它必须是history -cPrompt_COMMAND中间)。此版本还有两个重要的缺点:

    1. 历史记录文件必须初始化。它必须包含至少一个非空行(可以是任何东西)。
    2. history命令可能提供错误的输出-参见下文。

[编辑]“胜利者是...”

  • 选项3:

    HISTCONTROL=ignoredups:erasedups
    shopt -s histappend
    Prompt_COMMAND="history -n; history -w; history -c; history -r; $Prompt_COMMAND"
    

    就目前而言。only选项是使erasedups和公共历史记录同时工作。 This可能是您所有问题的最终解决方案,Aahan。


2.为什么option 2似乎不起作用(或:实际上/不能按预期工作)?

正如我提到的,上述每种解决方案的工作方式都不同。但是关于设置如何工作的最令人误解的解释来自分析history命令的输出。在许多情况下,该命令可以提供false输出。为什么?因为执行beforePrompt_COMMAND!中包含的其他history命令的顺序但是,当使用第二个或第三个选项时,可以监视.bash_history内容的变化(例如,使用watch -n1 "tail -n20 .bash_history"),并查看真实的历史记录。

3.为什么option 3如此复杂?

一切都取决于erasedups的工作方式。如bash手册所述,“(...)erasedups使与当前行匹配的所有先前行在保存该行之前从历史记录列表中删除”。因此,这确实是OP想要的(而不是像我以前认为的那样,没有重复出现按顺序。这就是每个history -.命令必须或不能在Prompt_COMMAND中的原因:

  • history -nhas要在history -w之前从.bash_history读取从任何其他终端保存的命令,

  • history -whas在那里,以便将历史记录保存到文件并删除重复项,

  • history -a必须放置在此处而不是history -w,因为它不会触发删除重复项,

  • history -c也是需要,因为它可以防止在每条命令后破坏历史记录缓冲区,

  • 最后,history -r需要以便从文件中恢复历史记录缓冲区,从而最终使历史记录在终端会话之间共享。

126
rozcietrzewiacz

在“提示”命令中,您正在使用-c开关。来自man bash

-c通过删除所有条目来清除历史记录列表

要与所有打开的终端共享您的历史记录,可以使用-n

-n将尚未从历史文件中读取的历史行读取到当前历史列表中。这些是自当前bash会话开始以来附加到历史文件的行。

默认大小也在手册中:

历史记录要在命令历史记录中记住的命令数(请参见下面的“历史记录”)。默认值为500。

要保存多行命令:

cmdhist Shell选项(如果启用)使Shell尝试将多行命令的每一行保存在同一历史记录条目中,并在必要时添加分号以保持语法正确性。 lithist Shell选项使Shell用嵌入式换行符而不是分号保存命令。

另外,您不应该在HIST *命令前加上export-它们是仅限bash的变量,而不是环境变量:HISTCONTROL=ignoredups:erasedups 足够了。

8
jasonwryan

这是我想出的,到目前为止,我对此感到满意……

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" 

笔记:

  • 是的,这很复杂...但是,它删除了所有重复项,但保留了每个终端中的时间顺序!
  • 我的HISTIGNORE会忽略所有没有参数的命令。这对于某些人来说可能不是理想的,可以忽略不计。
8
user41176

使用此代替:

HISTCONTROL=ignoreboth
1
verndog

它不起作用,因为您忘记了:

 -n   read all history lines not already read from the history file
      and append them to the history list

但似乎history -n只是export HISTCONTROL=ignoreboth:erasedups生效。

让我们尝试一下:

$ Prompt_COMMAND=
$ export HISTCONTROL=ignoreboth:erasedups
$ export HISTFILE=~/.bash_myhistory
$ HISTIGNORE='history:history -w'
$ history -c
$ history -w

在这里,我们打开复制擦除,将历史记录切换到自定义文件,清除历史记录。完成所有命令后,我们将获得空的历史记录文件,而当前历史记录中只有一个命令。

$ history
$ cat ~/.bash_myhistory
$ history
$ 1  [2019-06-17 14:57:19] cat ~/.bash_myhistory

打开第二个终端并运行这六个命令。之后:

$ echo "X"
$ echo "Y"
$ history -w
$ history
  1  [2019-06-17 15:00:21] echo "X"
  2  [2019-06-17 15:00:23] echo "Y"

现在,您当前的历史记录具有两个命令,历史记录文件具有:

#1560772821
echo "X"
#1560772823
echo "Y"

返回第一个终端:

$ history -n
$ history
1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
2  [2019-06-17 15:03:12] history -n

呵...没有读取echo命令。再次切换到第二个终端,然后:

$ echo "Z"
$ history -w

现在,历史文件为:

#1560772821
echo "X"
#1560772823
echo "Y"
#1560773057
echo "Z"

再次切换到第一个终端:

$ history -n
$ history
  1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
  2  [2019-06-17 15:03:12] history -n
echo "Z"

您可以看到echo "Z"命令合并到history -n

我认为,另一个bug是因为从历史记录中按命令编号而不是按命令时间读取命令。我希望其他echo个命令出现在历史记录中

0
Eugen Konkov

我在这里结合了多种答案:

  • 我希望历史记录最后合并,所以我使用了陷阱功能。
  • 我还希望历史记录文件由主机分隔,因此我将HISTFILE更改为指向目录,并根据主机名命名了文件。
  • 我添加了ignorespace选项,因此我可以键入明文密码,而不会在历史记录中显示它们,例如:$ ./.secretfunction -user myuser -password mypassword将不会保存,因为它以空格开头。
  • 我将history*exit添加到HISTIGNORE只是为了保留那些命令,包括诸如history | grep awesomecommand之类的历史记录,因为我通常不希望这样做。您可以添加其他内容,例如:注销,fg,bg等。
  • 然后,我将所有内容都放入我的〜/ .bash_aliases文件中,这样它就不会与升级冲突,因为有时会发生这种情况。
HISTCONTROL=ignoreboth:erasedups:ignorespace
HISTIGNORE="history*:exit"
HISTFILE=~/.bash_history/.$(hostname)_history
shopt -s histappend
function historymerge {
    history -n; history -w; history -c; history -r;
}
trap historymerge EXIT
Prompt_COMMAND="history -a; $Prompt_COMMAND"

Grep您的〜/作为Prompt_COMMAND,以确保您已使用历史记录-a修改了它。我还添加了我喜欢但未包含在上面的块中的TIME/DATE格式HISTTIMEFORMAT="%x %r %Z ",因为它是对语言环境敏感的。

0
Marlon

擦除前的空格和尾随的空格不会修剪(如某些语言的chomp)。这是一个错误。同样,擦除不删除所有先前的条目。

0
Sajith Nallithodi

结合使用@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"
  • historymerge函数从历史记录文件中加载会话外的行,将它们与会话历史记录合并,使用重复数据删除功能写出一个新的历史记录文件(从而挤压以前附加的重复行),然后重新加载历史记录。

  • 在提示符中保留history -a可以最大程度地减少丢失历史记录的可能性,因为它更新历史记录文件时不会对每个命令进行重复数据删除。

  • 最后,陷阱会在会话关闭时触发historymerge,以获取最新的清除历史记录文件,而最近关闭的会话的命令会冒泡到文件末尾(我认为)。

这样,每个终端会话从启动就将拥有自己的独立历史记录。我发现它更有用,因为我倾向于为不同的任务打开不同的终端(因此,每个任务都希望重复不同的命令)。与使多个终端不断尝试以分布式方式重新同步它们的有序历史记录相比,这要简单得多(尽管您仍然可以使用historymerge函数与选择会话或他们全部)。

请注意,您将希望大小限制足够大,以容纳所需的历史记录长度plus可以由所有并发活动会话添加的非重复数据删除行的数量。 5000对我来说足够了,这主要是由于广泛使用HISTIGNORE来过滤垃圾邮件的低价值命令。

0
HonoredMule