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

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

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

但在退出bash并按向上/向下箭头后,多行命令将分别显示为单独的条目,这是因为cat ~/.bash_history已将命令放在多个单独的条目上,并且书写问题这里;history命令结果也混乱了。

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

shopt -s cmdhist lithist
HISTTIMEFORMAT='%F %T '

现在书写问题已修复history命令仍然在多行和单独的条目中报告(阅读问题现在)。

Bash 版本为 4.3,v4.4 上存在同样的问题

此错误报告多年来一直没有解决方案。

更新:

还值得一提的是,下面的多行命令作为示例,即使在退出 Bash 后也能正确显示:

for i in {1..10}
do
echo $i
done

但这是失败的:

awk '
{ print $1}' <<<'first last'

更新 2:

上述问题已在 Bash v5.0.0+ 中修复,该问题已更改为将“时间戳作为分隔符”之间的条目识别为命令的单个条目(历史时间格式基督教教义岩石学家必须设置)。

答案1

我在用GNU bash,版本 5.0.3(1)-发布Ubuntu 19.10。我检查了一下,确认您问题中描述的问题确实存在。

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


#解决方案:

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

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

shopt -s cmdhist
shopt -s lithist
HISTTIMEFORMAT='%F %T '

来自 bash 手册页:

基督教教义

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

岩石学家

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

但是,当 shell 仍处于打开状态并从内存中运行时,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

因此,需要使用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

来自 bash 手册页:

历史时间格式

如果设置了此变量且不为空,则其值将用作 strftime(3) 的格式字符串,以打印与内置 history 显示的每个历史记录条目相关联的时间戳。如果设置了此变量,则时间戳将写入历史文件,以便它们可以在 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

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


注意:

  • 编辑并保存文件后,您需要重新启动当前 bash 会话~/.bashrc以激活更改。

  • 如果你的当前~/.bash_history文件或 bash 工作内存已经包含格式错误的历史记录行,则可能需要删除(请先备份history -w; history -c)通过在终端中运行来删除当前 bash 历史记录,这将永久删除所有当前 bash 历史记录。

  • 如果你想保留现有的历史记录,尽管旧条目被分成单行并带有占位符时间戳,那么按照上面的建议清除它。相反,备份.bash_history并编辑后.bashrc,运行此命令:

    sed -ri.bak '/^#[0-9]+$/{n;b};s/^/#42\n/' ~/.bash_history
    

    它会在每行之前添加一行#42(占位符时间戳),这些行不是时间戳,前面也没有时间戳。重新启动 bash 后,它应该可以正确存储和加载新的多行历史记录条目。要正确加载旧的多行,您可以.bash_history在文本编辑器中打开并删除#42多行内的所有行。

  • 如果 bash 一直拒绝正确加载多行,请确保第一的行中.bash_history是一个时间戳,即一个井号后跟一个数字(如#42,没有任何空格)。

相关内容