在 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 仍处于打开状态并从内存中运行时,cmdhist
和lithist
很有用。退出 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
因此,需要使用HISTTIMEFORMAT
which 作为分隔符,根据时间戳将每个命令与其他命令分开,无论是单行命令还是多行命令。因此文件~/.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
,没有任何空格)。