访问Zsh中的最后一个命令(不是以前的命令行)

时间:2014-08-13 20:07:36

标签: zsh

有没有办法在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)

相同的测试,其结果在最后一行有所不同。 Bash将命令行附加到历史记录,执行前(我不知道是否按规范),而Zsh似乎将命令行附加到历史记录,执行后(同样,我不知道它是否符合规范),因此history | tail -n1不会给出相同的内容。

我想要的是能够检索echo "This is command #2",即上一个命令的文本,即使它与其他命令在同一命令行上(当多个命令用{{1分隔时) }})。

使用bash,我可以使用;,但由于历史记录处理的不同,这对Zsh不再起作用。

需要做什么

如何在Zsh中从多命令命令行获取最后一个命令?

当命令需要知道前一个命令是什么时,我需要它,无论该命令是在同一行还是前一行。另一种说法,可能是:我需要访问单个面向命令的历史记录的最后一项,而不是命令行的历史记录。

3 个答案:

答案 0 :(得分:4)

据我所知,在zsh中没有简单的方法。我相信在交互式shell中对问题的最接近答案是使用历史记录扩展机制,尤其是!#,但您可能也对!!!!:1和其他人感兴趣。来自zsh手册:

  

!#请参阅当前输入的命令行   远。

因此,您可以执行以下操作以获取上一个命令:

echo "This is command #1"; var=$(echo !#) && echo "The previous command was:" \'$var\'

结果是

This is command #1
The previous command was: 'echo This is command #1'

你也可以玩

echo "This is command 1"; var=$(echo "!#:s/;//") && echo "The previous command was:" \'$var\'

如果您需要将!#括在双引号中,但在这种情况下,您必须从“last command”的末尾删除;:s/;//正在这样做。更复杂的命令现在运作良好:

ls >/dev/null 2>&1; var=$(echo "!#:s/;//") && print "The previous command was:" \'$var\'

给出输出:

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'

请注意,在这种情况下,#不应与引号一起出现在第一个命令中,因为它将被解释为注释。

注1

这里重要的是!#表示到目前为止当前行中的所有内容除了当前原子,因此表达式中的var

echo "This is command #1"; var=$(echo !#) && echo "The previous command was:" \'$var\'

实际上等于:

var=$(echo echo "This is command #1";)

以便echo $var如前所述打印echo This is command #1。 但是如果我们编写简化版本,没有变量:

echo "This is command #1"; echo "The previous command was:" !#

然后!#将包含额外的第二个echo及其参数,因此实际上命令将变为:

  

echo“这是命令#1”; echo“上一个命令是:”echo“这个   命令#1“; echo”上一个命令是:“

注2

这个解决方案显然并不完美,因为您可能已经注意到,引号不包含在变量中。您可以尝试通过在!# 附近添加单引号来解决此问题,但不能直接(否则历史记录扩展将不起作用)。

注3

如果一行中有超过3个或更多命令,以;分隔,则需要使用zsh修饰符或使用sed或awk等外部命令进行更多操作。

答案 1 :(得分:2)

试图回答我自己的问题。我仍然欢迎其他人的答案,因为这个答案并不完美。

至少,有一种方法可以使用$history数组和$HISTCMD索引与Bash相同。例如:

$ zsh
$ echo "This is command #3"; echo $history[$HISTCMD]
> This is command #3
> echo "This is command #3"; echo $history[$HISTCMD]

这与Bash中的history | tail -n1相同,我可以对此应用sed。但依靠sed正是这个答案不完全完美的原因;使用正则表达式解析命令行很容易出错,特别是使用与Zsh一样复杂的shell语法。

答案 2 :(得分:0)

您需要做的是!!,以重复上一条命令

如果要获取该命令的特定部分

!!:0将抓取第一个字符分组(直到到达空格分隔符)

!!:1将抓取第二个字符分组(直到到达空格分隔符)

以此类推...