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

DrB*_*eco 15 shell bash command-history signals

我知道这个问题并不晦涩,因为它在这里被问到不断更新(并在此处重复)。

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

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

shopt -s histappend
Run Code Online (Sandbox Code Playgroud)

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

我更喜欢这样做而不检查我输入的$PS1每一个command。我认为捕获某种信号会更好。你会怎么做?如果不可能,也许是一个简单的cronjob

我们如何解决这个难题?

Mic*_*mer 15

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

trap on_exit EXIT
trap on_usr1 USR1

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

on_usr1() {
    history -n
}
Run Code Online (Sandbox Code Playgroud)

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


它是如何工作的?

trap为系统信号或 Bash 的内部事件之一设置信号处理程序。该EXIT事件是外壳的任何控制终止,而USR1SIGUSR1,我们占有一个毫无意义的信号。

每当 shell 退出时,我们:

  • 明确地将所有历史记录附加到文件中。
  • 禁用SIGUSR1处理程序并使这个 shell忽略信号。
  • bash从同一用户向所有正在运行的进程发送信号。

当 aSIGUSR1到达时,我们:

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

因为这样猛砸手柄信号,你就不会真正得到新的历史数据,直到你打Enter接下来的时间,所以这不会做对前面的任何优于把history -nPROMPT_COMMAND。但是,它确实会在没有发生任何事情时不断读取文件,并且在 shell 退出之前根本没有写入。


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

trap '' USR1
Run Code Online (Sandbox Code Playgroud)

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

最后,虽然这符合您的要求,但您得到的订单会有点不寻常。特别是,当历史片段被分别加载和保存时,它们会以不同的顺序重复。这本质上是您所要求的内容,但请注意,此时向上箭头历史变得不那么有用了。不过,历史替换等将被共享并且运行良好。