在多个终端窗口中保存Bash历史记录
1. 概述
在某些情况下,我们可能会在多个终端上使用同一个 Linux 用户的登录会话。在这种情况下,我们希望以连续且一致的方式保留在不同终端上触发的命令序列。
在本教程中,我们将研究在多个终端窗口中保留 Bash历史记录 的方法。首先,我们将了解 Bash history的默认行为。然后,我们将探索跨多个会话保持历史一致性的方法。最后,我们将得出问题陈述的解决方案。
2. Bash 历史及其默认行为
我们可以使用 history 命令检查在 Linux 终端上执行的history命令序列:
$ history
要从history中过滤掉最后n 个命令,我们可以提供数字作为附加选项:
$ history 7
这列出了 Bash历史记录中的最后 7 个条目:
$ history 7
112 ls -lrt
113 cat debug9.sh
114 echo "Hello" >| temp.txt
115 set -o | grep noclobber
116 ls -lrt | tail -2 && cat temp.txt
117 echo $PROMPT
118 history 7
默认情况下,用户主目录中的.bash_history文件存储在终端上执行的命令序列。但是我们可以通过设置一个特殊的* shell 变量* $HISTFILE*来更改文件路径和名称*。我们将在本教程后面看到这一点。
当 Bash shell 在用户登录时以交互方式加载时,它会将*$HISTFILE的内容读入内存。在 shell 会话期间,它会将内容添加到内存文件中。当 shell 退出时,它会将内存的内容写回到$HISTFILE file*上的磁盘。
但是,我们应该在这里注意,可以写回磁盘的最大行数是有限制的。我们可以通过另一个 shell 变量*$HISTSIZE*来调整这个限制:
$ echo $HISTSIZE
1000
此处如HISTSIZE中所指定,我们的 Bash 历史记录最多可包含 1000 个条目。假设该文件已经有 900 个条目,并且在我们的会话运行期间,**添加了 150 个新条目。**在这种情况下,在 Bash 退出后,文件的前 50 个条目将丢失,因为我们已将HISTFILE设置为仅包含 1000 个最新条目。
3. 启用文件附加选项
之前,我们讨论过**当 Bash 退出时,它会将内存中的历史记录转储到磁盘文件中。因此,每次我们退出 Bash 交互式登录时,历史文件都会被覆盖。当我们有多个 Bash 会话/终端处于活动状态时,此行为会产生影响,**因为HISTFILE将仅包含最后一个退出 shell 的内容。
但是,**我们可以使用内置shopt **启用历史附加选项:
$ shopt -s histappend
我们可以将此命令添加到*~/.bashrc文件中,以防止在 shell 退出时覆盖HISTFILE* 。
4. 每个命令后同步历史文件
至此,我们已经解决了在 Bash 退出时维护历史文件的问题。但是,**我们希望所有会话的历史记录能够实时同步。*为了解决这个问题,我们需要找到一种方法来更新HISTFILE。我们可以使用history命令的-a*选项将当前会话历史附加到历史文件的内容中:
$ history -a
这为我们提供了一个选项,可以根据需要在HISTFILE中附加会话历史记录。但是我们希望在每次命令执行之后进行追加。为了解决这个问题,我们可以将历史追加选项添加到PROMPT_COMMAND :
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a"
Bash在打印每个主要提示之前检查变量PROMPT_COMMAND的值。我们可以将上述命令添加到*~/.bashrc文件中。这确保了PROMPT_COMMAND*的值对于所有终端都是相同的。
5. 一般解决方案
我们现在可以将以下条目添加到*~/.bashrc*以解决我们的主要问题:
$ shopt -s histappend
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a"
让我们进一步优化解决方案:
$ shopt -s histappend
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"
在这里,通过添加history -c我们确保我们清除当前保存在内存中的所有历史记录条目。稍后通过添加history -r我们将HISTFILE的内容重新加载到内存中。
让我们看看这付诸行动:
$ tail -2 .bashrc
shopt -s histappend
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"
$ pstree
init─┬─init───bash───pstree
├─2*[init───bash]
└─{init}
我们验证了*.bashrc文件的内容,并从终端 1执行了*pstree 命令。我们还登录了另外两个终端,我们可以通过pstree命令的输出来验证。现在让我们从另一个终端(Terminal2)执行一些操作:
$ echo "This one is from Terminal 2"
This one is from Terminal2
我们将再次切换到新终端(Terminal 3):
$ echo "Terminal 3 here.. "
Terminal 3 here..
现在我们将回到我们最初的终端来验证history命令:
$ echo "Checking from Terminal 1" && history 5
Checking from Terminal 1
8 tail -2 .bashrc
9 pstree
10 echo "This one is from Terminal 2"
11 echo "Terminal 3 here.. "
12 echo "Checking from Terminal 1" && history
正如我们从输出中看到的那样,历史记录以顺序方式存储,并且在所有终端之间保持同步。
6. 每个终端单独的历史文件
**有时我们可能希望为每个 Bash 会话保留单独的日志。**在这种情况下,我们还可以为每个终端创建一个单独的历史文件:
$ export HISTFILE=$HOME/.myhistfile.$$
由于*$$*保存当前 shell 的进程 ID,因此它将为每个会话创建一个单独的历史文件。但是,在这种情况下,命令或查看历史的反向搜索将仅显示当前会话(终端)的结果。此方法最适合为审计目的保留会话历史记录。