跨会话共享 shell 历史记录而不交错

跨会话共享 shell 历史记录而不交错

有一个类似的问题这里,但我想实现不同的目标:我想在会话之间共享历史记录,但是无需将不同会话中执行的命令混合在一起。

例如,假设我有两个 shell 会话:A 和 B。我在 A 中键入一些命令:

A$ ls ~
A$ ls /etc

在B中:

B$ git status
B$ git log

当我输入historyshell 时,我想查看该 shell 中的所有命令一起,来自其他 shell 的命令 - 这样我总是可以使用 uparrow 从当前 shell 获取最后的命令。换句话说,history在 shell A 中应该显示

git status
git log
ls ~
ls /etc

在 shell B 中它应该显示

ls ~
ls /etc
git status
git log

这个怎么做?

答案1

似乎没有内置的解决方案,但事实证明手动实现它并不那么困难。人们必须单独存储每个会话的历史记录,并在每次提示时重新创建它(它并不像听起来那么慢)。核心逻辑如下:

# on every prompt, save new history to dedicated file and recreate full history
# by reading all files, always keeping history from current session on top.
update_history () {
  history -a ${HISTFILE}.$$
  history -c
  history -r
  for f in `ls ${HISTFILE}.[0-9]* | grep -v "${HISTFILE}.$$\$"`; do
    history -r $f
  done
  history -r "${HISTFILE}.$$"
}
export PROMPT_COMMAND='update_history'

# merge session history into main history file on bash exit
merge_session_history () {
  cat ${HISTFILE}.$$ >> $HISTFILE
  rm ${HISTFILE}.$$
}
trap merge_session_history EXIT

这个要点完整的解决方案,包括一些保障措施和性能优化。

答案2

这并不完全是问题的答案,但仍然非常相似,所以有些人可能会觉得很有趣:

我的直觉是,uparrow 应该根据当地历史行事,但也Ctrl-r应该根据全球共同历史行事。这是一种方法(使用 fzf):

# do not overwrite the history file on exit
shopt -s histappend

# immediately add the last command to the history file
PROMPT_COMMAND="history -a; $PROMPT_COMMAND"

# use a custom function that uses $HISTFILE for Ctrl-r
__my_history__() {
    READLINE_LINE=$(fzf --query "$READLINE_LINE" < $HISTFILE)
    READLINE_POINT=${#READLINE_LINE}
}
bind -x '"\C-r": __my_history__'

相关内容