将 bash 历史记录中的多行命令块分成多行

αғs*_*нιη 11 bash history bash-history

在 Bash(以及 WSL 中的 Bash)中,多行编写的命令可以使用向上/向下箭头正确回调,内置history命令也可以正确报告它们(直到我仍然登录 bash)。

但是在退出bash并按下向上/向下箭头后,多行命令每个都显示为单独的条目,这是因为cat ~/.bash_history已将命令放在多个单独的条目上并在此处写入问题;该history命令的结果搞砸了。

我已经设置了这些选项 ~/.bashrc

shopt -s cmdhist lithist
HISTTIMEFORMAT='%F %T '
Run Code Online (Sandbox Code Playgroud)

现在写入问题已修复,history命令仍以多行和单独的条目报告(现在读取问题)。

Bash 版本是 4.3,在 v4.4 上有同样的问题

多年来一直有这个错误报告,但还没有解决方案。

更新:

还要提到的是,即使在退出 Bash 之后,以下多行命令作为示例也能正确显示:

for i in {1..10}
do
echo $i
done
Run Code Online (Sandbox Code Playgroud)

但这失败了:

awk '
{ print $1}' <<<'first last'
Run Code Online (Sandbox Code Playgroud)

更新 2:

上面提到的问题在 Bash v5.0.0+ 中得到修复,该问题已更改为将“时间戳作为分隔符”之间的条目识别为命令的单个条目(必须设置HISTTIMEFORMATcmdhistlithist)。

Raf*_*ffa 10

我在Ubuntu 19.10上使用GNU bash,版本 5.0.3(1)-release。我检查并确认您的问题中描述的问题存在。

然后我使用以下步骤解决了它。之后我多次退出 bash 并确认问题已在我的系统上解决。多行命令被保存到~/.bash_history文件中,被正确检索和执行。


解决方案:

如果~/.bashrc文件不存在,请编辑您的文件或创建它。

将以下三行复制并粘贴到其中并保存:

shopt -s cmdhist
shopt -s lithist
HISTTIMEFORMAT='%F %T '
Run Code Online (Sandbox Code Playgroud)

从 bash 手册页:

cmdhist

如果设置,bash 会尝试将多行命令的所有行保存在同一历史条目中。这允许轻松重新编辑多行命令。

石器

如果设置,并且启用了 cmdhist 选项,多行命令将使用嵌入的换行符保存到历史记录中,而不是在可能的情况下使用分号分隔符。

然而,cmdhistlithist而壳仍然是开放的,并从内存的工作是有用的。当您退出 shell 时,命令将~/.bash_history作为单行保存到文件中,而没有任何关于多行命令开始或结束位置的指示,然后清除工作内存。当您再次运行 shell 时,bash 历史文件(包括多行命令)中的这些行将被一次读取一行,并且每一行都将作为单个命令处理并加载到工作内存中,即使它可能是一个多行命令的一部分,因为~/.bash_history文件将如下所示:

nano .bashrc 
exit
history 
for i in {1..10}
do
echo $i
done
cat .bash_history 
exit
history 
awk '
{ print $1}' <<<'first last'
history
exit
Run Code Online (Sandbox Code Playgroud)

因此,需要将HISTTIMEFORMATwhich 用作分隔符,根据时间戳将每个命令与其他命令分开,无论是单行命令还是多行命令。所以~/.bash_history文件看起来像这样:

nano .bashrc 
#1581635697
exit
#1581635709
history 
#1581635729
for i in {1..10}
do
echo $i
done
#1581635743
cat .bash_history 
#1581635757
exit
#1581635773
history 
#1581635794
awk '
{ print $1}' <<<'first last'
#1581635801
history
#1581635808
exit
Run Code Online (Sandbox Code Playgroud)

从 bash 手册页:

历史时间格式

如果此变量已设置且不为空,则其值将用作 strftime(3) 的格式字符串,以打印与历史内置程序显示的每个历史条目关联的时间戳。如果设置了此变量,时间戳将写入历史文件,以便在 shell 会话中保留它们。这使用历史注释字符来区分时间戳与其他历史行。

从现在开始,多行命令将作为一个整体被检索、处理并加载到工作内存中(不将它们分成单行并将每一行视为一个单独的命令)并且history命令输出将如下所示(即使在重新启动 bash 之后) :

raffa@Laptop:~$ history
   1  2020-02-14 05:25:19 nano .bashrc 
   2  2020-02-14 05:25:38 exit
   3  2020-02-14 05:25:50 history
   4  2020-02-14 05:27:50 for i in {1..10}
do
echo $i
done
   5  2020-02-14 05:28:05 cat .bash_history
   6  2020-02-14 05:28:14 exit
   7  2020-02-14 05:28:27 history
   8  2020-02-14 05:28:55 awk '
{ print $1}' <<<'first last'
   9  2020-02-14 05:29:06 history
  10  2020-02-14 05:29:16 exit
  11  2020-02-14 05:29:27 history
Run Code Online (Sandbox Code Playgroud)

退出后,多行命令将被正确检索、显示和执行。


注意:

  • 在编辑并保存~/.bashrc文件以激活更改后,您需要重新启动当前的 bash 会话。
  • 如果您当前的~/.bash_history文件或 bash 工作内存已经包含格式错误的历史记录行,您可能需要通过在终端中运行来删除(请先备份)当前的 bash 历史记录,history -w; history -c这将永久删除您当前的所有 bash 历史记录。

祝你好运

  • 好的,我已经安装了 Bash v5.0.0,似乎它已修复,我发现了这些更改注释。`如果 readline 读取以“#”(或历史注释字符的值)开头的历史文件并且启用了历史时间戳,则假定历史条目由时间戳分隔。这允许多行历史记录条目。` &amp;&amp; `在执行增量搜索时键入 ^M 时的 bash-1.14 行为已恢复。^J 现在可用于终止搜索而不接受该行。` (2认同)
  • &gt; 如果 bash 一直拒绝正确加载多行,请确保 .bash_history 中的第一行是时间戳,即是一个哈希值后跟一个数字(如 #42,没有任何空格)。——这对我来说很重要。看来我的历史文件在文件开头被错误地截断了,所以我可以保存多行历史记录,但“history”命令仍然将每一行显示为单独的命令。 (2认同)