退出一个终端时更新其他终端上的 bash 历史记录

退出一个终端时更新其他终端上的 bash 历史记录

我知道这个问题并不晦涩,因为它被问到了这里持续更新(和重复的这里)。

我想要实现的目标有点不同。我不喜欢每次ls键入 ( history -a; history -c; history -r) 时都会提示重写文件的想法。

我想在退出时更新文件。这很简单(实际上是默认的),但是您需要追加而不是重写:

shopt -s histappend

现在,当一个终端关闭时,我想让所有其他保持打开状态的终端都知道更新。

我更喜欢在不检查我输入的$PS1每一个command内容的情况下执行此操作。我认为捕获某种信号会更好。你会怎么做?如果不可能,也许一个简单的cronjob

我们怎样才能解决这个难题呢?

答案1

你说创意和涉及信号?好的:

trap on_exit EXIT
trap on_usr1 USR1

on_exit() {
    history -a
    trap '' USR1
    killall -u "$USER" -USR1 bash
}

on_usr1() {
    history -n
}

把它放进去.bashrc然后走。这使用信号告诉每个bash进程在另一个进程退出时检查新的历史记录条目。这非常糟糕,但确实有效。


它是如何工作的?

trap设置信号处理程序对于系统信号或 Bash 的内部事件之一。该EXIT事件是 shell 的任何受控终止,而USR1is 是SIGUSR1我们占用的无意义信号。

每当 shell 退出时,我们:

  • 将所有历史记录显式附加到文件中。
  • 禁用SIGUSR1处理程序并创建此 shell忽略信号。
  • 将信号发送到bash同一用户的所有正在运行的进程。

当 aSIGUSR1到达时,我们:

  • 将历史文件中的所有新条目加载到 shell 的内存历史列表中。

由于 Bash 处理信号的方式,在Enter下次点击之前,您实际上不会获得新的历史数据,因此这在这方面并没有比输入更好history -n进入PROMPT_COMMAND。不过,当没有发生任何事情时,它确实会不断地读取文件,并且在 shell 退出之前根本不会进行写入。


然而,这里仍然存在一些问题。第一个是默认响应SIGUSR1是终止贝壳。任何其他bash进程(例如运行 shell 脚本)都将被终止。.bashrc不由非交互式 shell 加载。反而,一个名为的文件BASH_ENV加载了:您可以在全局环境中设置该变量以指向文件:

trap '' USR1

其中忽略其中的信号(这解决了问题)。

最后,虽然这满足了您的要求,但您得到的顺序会有点不寻常。特别是,当历史记录被单独加载和保存时,它们将以不同的顺序重复。这本质上是您所要求的固有内容,但请注意,此时向上箭头历史记录的用处要小得多。历史换人不过,类似的内容将被共享并且运行良好。

相关内容