在里面bash 参考手册它指出:
lithist
如果启用,并且cmdhist
启用该选项,多行命令将使用嵌入的换行符保存到历史记录中,而不是尽可能使用分号分隔符。
因此我的问题是:何处/何时/如何可能?
我尝试在我的设备上启用并测试该功能GNU bash,版本 4.4.12(1)-发布这样做:
shopts -s cmdhist
shopts -s lithist
echo -n "this is a test for a ";\
echo "multiline command"
然后我做了一个
history | tail
期待一些类似于这样的输出:
101 shopts -s cmdlist
102 shopts -s lithist
103 echo -n "this is a test for a ";\
echo "multiline command"
104 history
但得到这个:
101 shopts -s cmdlist
102 shopts -s lithist
103 echo -n "this is a test for a "; echo "multiline command"
104 history
很明显,多行命令(bash 历史记录编号为 103 的命令)尚未存储“嵌入换行符而不是使用分号分隔符”。为什么lithist
在这里不可能?我做错了什么?
答案1
A\<new line>
不是<new line>
在历史中获取 a 的正确方法。
记忆
我们只处理历史行,因为它们保存在 shell 内存(而不是磁盘)中。
让我们像您一样输入几个命令:
$ echo -n "this is a test for a ";\
> echo "two line command"
当刚刚写入的行时,内存中存储了什么?
$ history 2
514 echo -n "this is a test for a ";echo "two line command"
515 history 2
正如您所看到的,“行继续”(反斜杠后跟换行符)已被删除。
正如它应该的那样(来自 man bash):
如果出现 \ 对,并且反斜杠本身没有被引号引起来,则 \ 被视为行延续(即,它会从输入流中删除并被有效忽略)。
如果我们引用它,我们可能会得到一个换行符:
$ echo " A test of
> a new line"
A test of
a new line
并且,在这一点上,历史将反映出:
$ history 2
518 echo "A test of
a new line"
519 history 2
真正的多行命令:
多行命令的一个可能示例是:
$ for a in one two
> do echo "test $a"
> done
test one
test two
如果满足以下条件,则该历史记录将折叠为一行cmdhist is set
:
$ shopt -p cmdhist lithist
shopt -s cmdhist
shopt -u lithist
$ history 3
24 for a in one two; do echo "test $a"; done
25 shopt -p cmdhist lithist
26 history 3
每个命令的数字都发生了变化,因为在某个时刻我使用 .clear 清除了历史记录(在内存中)history -c
。
如果您取消设置 cmdhist,您将得到以下信息:
$ shopt -u cmdhist
$ for a in one two
> do echo "test $a"
> done
test one
test two
$ history 5
5 shopt -u cmdhist
6 for a in one two
7 do echo "test $a"
8 done
9 history 5
每行(不是完整的命令)将位于历史记录中的单独行。
即使lithist
设置了:
$ shopt -s lithist
$ for a in one two
> do echo "test $a"
> done
test one
test two
$ history 5
12 shopt -s lithist
13 for a in one two
14 do echo "test $a"
15 done
16 history 5
但如果两者都设置了:
$ shopt -s cmdhist lithist
$ for a in one two
> do echo "test $a"
> done
$ history 5
23 history 15
24 shopt -p cmdhist lithist
25 shopt -s cmdhist lithist
26 for a in one two
do echo "test $a"
done
27 history 5
该for
命令存储为多行命令,并使用“换行符”而不是分号 ( ;
)。与上面未设置 lithist 的情况进行比较。
磁盘
上述所有内容都是使用 shell 内存中保存的命令列表进行解释的。没有命令写入磁盘。 (默认)文件~/.bash_history
未更改。
当正在运行的 shell 退出时,该文件将被更改。届时,历史记录将覆盖该文件(如果histappend
未设置),或者以其他方式附加。
如果您希望将命令提交到磁盘,您需要有这套:
export PROMPT_COMMAND='history -a'
这将使每个命令行都附加到每个新命令行上的文件中。
现在,让我们开始讨论 cmdhist 和 lithist。事情并不像看起来那么简单。但别担心,一切很快就会清楚。
假设您花时间输入下面的所有命令(没有快捷方式,没有别名,没有功能,您需要实际的命令,抱歉)。
首先清除内存 ( history -c
) 和磁盘 (进行备份) ( history -w
) 然后尝试 3 次:
- 使用默认值cmdhist(设置)和lithist(未设置)。
- 同时设置
- 两者均未设置
- 使用未设置的 cmdhist 设置 lithist 是没有意义的(您可以测试它)。
要执行的命令列表:
$ history -c ; history -w # Clear all history ( Please backup).
$ shopt -s cmdhist; shopt -u lithist
$ for a in one two
> do echo "test $a"
> done
$ shopt -s cmdhist; shopt -s lithist
$ for a in one two
> do echo "test $a"
> done
$ shopt -u cmdhist; shopt -u lithist
$ for a in one two
> do echo "test $a"
> done
你将以这个结束(在记忆中):
$ history
1 shopt -s cmdhist; shopt -u lithist
2 for a in one two; do echo "test $a"; done
3 shopt -s cmdhist; shopt -s lithist
4 for a in one two
do echo "test $a"
done
5 shopt -u cmdhist; shopt -u lithist
6 for a in one two
7 do echo "test $a"
8 done
9 history
三个多行命令的结尾如下:
- 编号为 2 的行中的一个(一行,一个命令)。
- 编号为 4 的多行中的一个(多行中的一个命令)
- 编号从 6 到 8 的几行之一
好的,但是文件中发生了什么?已经说过了....
最后,在文件中:
很简单,写入文件并对其进行 cat 即可看到:
$ history -w ; cat "$HISTFILE"
shopt -s cmdhist; shopt -u lithist
for a in one two; do echo "test $a"; done
shopt -s cmdhist; shopt -s lithist
for a in one two
do echo "test $a"
done
shopt -u cmdhist; shopt -u lithist
for a in one two
do echo "test $a"
done
history
history -w ; cat "$HISTFILE"
没有行号,只有命令,没有办法知道多行从哪里开始和结束。即使有多行也没有办法判断。
事实上,这正是发生的情况,如果将命令如上所述写入文件,则读回文件时,有关多行的任何信息都会丢失。
只有一个分隔符(换行符),每一行都作为一个命令读回。
有没有解决方案,是的,使用额外的分隔符。
HISTTIMEFORMAT 就是这样做的。
历史时间格式
当此变量设置为某个值时,执行每个命令的时间将作为自纪元以来的秒数(是的,始终是秒)存储在文件中,位于注释 ( #
) 字符之后。
如果我们设置变量并重写文件~/.bash_history
,我们会得到:
$ HISTTIMEFORMAT='%F'
$ history -w ; cat "$HISTFILE"
#1490321397
shopt -s cmdhist; shopt -u lithist
#1490321397
for a in one two; do echo "test $a"; done
#1490321406
shopt -s cmdhist; shopt -s lithist
#1490321406
for a in one two
do echo "test $a"
done
#1490321418
shopt -u cmdhist; shopt -u lithist
#1490321418
for a in one two
#1490321418
do echo "test $a"
#1490321420
done
#1490321429
history
#1490321439
history -w ; cat "$HISTFILE"
#1490321530
HISTTIMEFORMAT='%FT%T '
#1490321571
history -w ; cat "$HISTFILE"
现在您可以知道哪里以及哪条线是多线。
该格式'%FT%T '
仅在使用历史命令时显示时间:
$ history
1 2017-03-23T22:09:57 shopt -s cmdhist; shopt -u lithist
2 2017-03-23T22:09:57 for a in one two; do echo "test $a"; done
3 2017-03-23T22:10:06 shopt -s cmdhist; shopt -s lithist
4 2017-03-23T22:10:06 for a in one two
do echo "test $a"
done
5 2017-03-23T22:10:18 shopt -u cmdhist; shopt -u lithist
6 2017-03-23T22:10:18 for a in one two
7 2017-03-23T22:10:18 do echo "test $a"
8 2017-03-23T22:10:20 done
9 2017-03-23T22:10:29 history
10 2017-03-23T22:10:39 history -w ; cat "$HISTFILE"
11 2017-03-23T22:12:10 HISTTIMEFORMAT='%F'
12 2017-03-23T22:12:51 history -w ; cat "$HISTFILE"
13 2017-03-23T22:15:30 history
14 2017-03-23T22:16:29 HISTTIMEFORMAT='%FT%T'
15 2017-03-23T22:16:31 history
16 2017-03-23T22:16:35 HISTTIMEFORMAT='%FT%T '
17 2017-03-23T22:16:37 history
答案2
这似乎不是一个多行命令(因为您逃避了返回)。如果你做的是有实际回报的事情,那就有区别了。
$ for i in /tmp/g*
> do echo $i
> done
/tmp/gigabyte
$ shopt -s lithist
$ for i in /tmp/g*
> do echo $i
> done
/tmp/gigabyte
$ history
[...]
517 for i in /tmp/g* ; do echo $i ; done
518 shopt -s lithist
519 for i in /tmp/g*
do echo $i
done
520 history
答案3
iTerm完美地处理多行命令,它将多行命令保存为一个命令,然后我们可以使用++Cmd来导航历史记录。查看更多 iTerm 提示:Shift;使用 iTerm 有效工作
答案4
我试过shopt -s lithist cmdhist
。
但是注销和登录后,历史记录恢复~/.bash_history
仍然分为多行:
1953 2019-05-23 16:57:53 shopt -s cmdhist; shopt -s lithist
1954 2019-05-23 16:57:58 for i in 1 2 3
1955 2019-05-23 16:58:34 do echo $i
1956 2019-05-23 16:58:34 done
1957 2019-05-23 16:58:08 history 5
1958 2019-05-23 16:58:27 history -a
1959 2019-05-23 16:54:12 history 10 | less
这种行为是预期的吗?
以下是我的内容~/.bash_history
:
#1558601873
shopt -s cmdhist; shopt -s lithist
#1558601878
for i in 1 2 3
do echo $i
done
#1558601888
history 5
#1558601907
history -a
#1558601652
history 10 | less
解决方案
我通过删除旧的 ~/.bash_history 来解决这个问题,然后多行历史记录工作正常;即使在注销并登录后。
1 2019-06-12 13:53:11 \rm .bash_history
2 2019-06-12 13:53:27 fx mcd
3 2019-06-12 13:53:28 mcd ()
{
mkdir $@;
cd $1
}
4 2019-06-12 14:55:14 nmcli-restart-hotspot -s
5 2019-06-12 21:34:35 ssh lab
6 2019-06-12 23:38:45 history | less