有没有办法在Zsh中检索最后一个命令的文本?我的意思是最后执行的命令,而不是最后一个命令行。
为了做到这一点,我发现Zsh和Bash处理历史记录之间存在细微的区别。以下示例暴露了这种差异,这是我在Bash中所做的基础,而在Zsh中则无效。
$ zsh
$ echo "This is command #1"
> This is command #1
$ echo "This is command #2"; echo $(history | tail -n1)
> This is command #2
> 3807 echo "This is command #1"
$ bash
$ echo "This is command #1"
> This is command #1
$ echo "This is command #2"; echo $(history | tail -n1)
> This is command #2
> 4970 echo "This is command #2"; echo $(history | tail -n1)
Run Code Online (Sandbox Code Playgroud)
相同的测试,其结果在最后一行有所不同。Bash 在执行之前将命令行添加到历史记录中(我不知道它是否按规范执行),而Zsh似乎在执行之后将命令行添加到历史记录中(相同,我不知道它是否按规范执行) ),因此history | tail -n1
不相同。
我想要的是echo "This is command #2"
即使在与其他命令位于同一命令行的情况下(当多个命令用分隔时;
),也能够检索到前一条命令的文本。
使用bash时,我可以使用history | tail -n1 | sed ...
,但由于历史记录处理方面的差异,因此Zsh不能再使用了。
关于如何从Zsh中的多命令行命令行获取最后一条命令的任何想法吗?
当命令需要知道上一条命令是什么时,无论该命令在同一行还是在上一行,我都需要它。另一种说法是:我需要访问单个面向命令的历史记录的最后一项,而不是面向行的命令的历史记录的最后一项。
试图回答我自己的问题。我仍然欢迎其他人的答案,因为这个并不完美。
至少,有一种方法可以使用$history
数组和$HISTCMD
索引获得与 Bash 相同的方法。例子:
$ zsh
$ echo "This is command #3"; echo $history[$HISTCMD]
> This is command #3
> echo "This is command #3"; echo $history[$HISTCMD]
Run Code Online (Sandbox Code Playgroud)
这与history | tail -n1
Bash 中的相同,我可以sed
对此进行应用。但依赖sed
正是这个答案不完全完美的原因;使用正则表达式解析命令行很容易出错?尤其是使用与 Zsh 一样复杂的 shell 语法。
小智 5
据我所知,在 zsh 中没有简单的方法。我认为最接近的答案,在交互的shell你的问题是使用历史扩展机制,特别是!#
,但你可能感兴趣的!!
,!!:1
和其他的方面。从 zsh 手册:
!# 参考目前输入的当前命令行。
因此,您可以执行以下操作来获取上一个命令:
echo "This is command #1"; var=$(echo !#) && echo "The previous command was:" \'$var\'
Run Code Online (Sandbox Code Playgroud)
结果是
This is command #1
The previous command was: 'echo This is command #1'
Run Code Online (Sandbox Code Playgroud)
你也可以玩
echo "This is command 1"; var=$(echo "!#:s/;//") && echo "The previous command was:" \'$var\'
Run Code Online (Sandbox Code Playgroud)
如果您需要!#
用双引号括起来,但在这种情况下,您必须;
从“最后一个命令”的末尾删除。:s/;//
正在这样做。更复杂的命令现在运行良好:
ls >/dev/null 2>&1; var=$(echo "!#:s/;//") && print "The previous command was:" \'$var\'
Run Code Online (Sandbox Code Playgroud)
给出输出:
ls >/dev/null 2>&1; var=$(echo "ls >/dev/null 2>&1") && print "The previous command was:" $var
The previous command was: 'ls >/dev/null 2>&1'
Run Code Online (Sandbox Code Playgroud)
但是请注意,在这种情况下#
,第一个命令中不应与引号一起出现,因为它将被解释为注释。
注 1
在这里重要的是!#
表示到目前为止当前行中存在的所有内容,但当前原子除外,因此var
在表达式中
echo "This is command #1"; var=$(echo !#) && echo "The previous command was:" \'$var\'
Run Code Online (Sandbox Code Playgroud)
实际上等于:
var=$(echo echo "This is command #1";)
Run Code Online (Sandbox Code Playgroud)
以便像前面提到的那样echo $var
打印echo This is command #1
。但是如果我们写简化版,没有变量:
echo "This is command #1"; echo "The previous command was:" !#
Run Code Online (Sandbox Code Playgroud)
then!#
将包含附加的、第二个echo
及其参数,因此实际上命令将变为:
echo "这是命令 #1"; echo "上一个命令是:" echo "这是命令 #1"; echo "上一个命令是:"
笔记2
这个解决方案显然并不完美,因为您可能已经注意到,引号没有包含在变量中。您可以尝试通过在周围附加单引号!#
而不是直接附加单引号来解决它(否则历史扩展将不起作用)。
注 3
如果您在一行中有超过 3 个或更多的命令,用 , 分隔;
,那么您需要更多地使用 zsh 修饰符或外部命令(如 sed 或 awk)。