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


15

我知道这个问题并不是很模糊,因为这里的问题一直在更新(这里重复)。

我想要达到的目标有些不同。我不喜欢每次ls输入(history -a; history -c; history -r)时都会立即重写文件的想法。

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

shopt -s histappend

现在,当终端关闭时,我想让所有其他保持打开状态以了解更新。

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

我们如何解决这个难题?


1
请注意,zsh开箱即用(并且有许多选项可以微调历史记录共享)。
吉尔斯(Gillles)“所以-别再邪恶了”

谢谢@吉尔斯; 有趣的是,使用Linux多年,但我从未尝试过任何其他方法bash。也许是时候找些新东西了,只是为了好玩。
Beco博士

Answers:


15

您说创意和涉及信号吗?好:

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事件是外壳的任何控制终止,而USR1SIGUSR1,我们占有一个毫无意义的信号。

每当外壳退出时,我们:

  • 明确将所有历史记录追加到文件中。
  • 禁用SIGUSR1处理程序,并使该外壳程序忽略该信号。
  • 将信号bash从同一用户发送到所有正在运行的进程。

SIGUSR1到达时,我们:

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

由于Bash处理信号的方式,您直到Enter下一次点击时才真正获得新的历史数据,因此在这方面并没有比history -n放进去更好PROMPT_COMMAND。但是,即使什么也没有发生,它确实可以节省不断读取文件的时间,并且在shell退出之前根本没有写入操作。


但是,这里仍然有几个问题。首先是默认响应SIGUSR1是终止 shell。任何其他bash进程(例如正在运行的Shell脚本)将被杀死。.bashrc不是由非交互式外壳加载的。相反,BASH_ENV加载名为的文件:您可以在环境中全局设置该变量以指向具有以下内容的文件:

trap '' USR1

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

最后,尽管这样做可以满足您的要求,但是您得到的订购将有些不寻常。特别是,历史记录的各个部分在分别加载和保存时将以不同的顺序重复。这本质上是您要的内容,但是请注意,向上箭头的历史记录在这一点上变得不那么有用了。但是,历史记录替换之类的东西将被共享并很好地工作。


我想知道您是否在.bashrc文件中启用了时间戳记,然后出现了诸如cronjob之类的东西并定期SIGUSR1重新请求该文件,并按照您的代码片段发送了一个信息,是否可以恢复按时间顺序排列的向上箭头历史记录?
2015年

这是一个很好的解决方案,但事实上其他进程在USR1上终止。USR2是否也会发生这种现象?
Beco博士

我会添加第二条评论,因为我很惊讶。流程如何将TERM与USR1关联?USR1不是仅供用户使用的东西吗?这是一些linux bug吗?为什么其他程序正在捕获USR1?(我知道这里不打算讨论这个问题,但是也许我会在正确的地方发现它)
Beco博士

几乎所有信号的默认行为都是终止。它在POSIX中指定。这不是错误。Bash让您指定在所有过程中都会忽略该信号,因此对于我们的目的而言是很好的。
Michael Homer 2015年

谢谢@MichaelHomer。您是否BASH_ENV按照此答案中的说明完成了本规范?还是您知道一种更标准的方法来消除这种邪恶?
Beco博士
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.