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

问题描述 投票:6回答:3

有没有办法在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",即上一个命令的文本,即使它与其他命令在同一命令行上(当有多个命令用;分隔时)。

使用bash,我可以使用history | tail -n1 | sed ...,但由于历史处理的不同,这对Zsh不再起作用。

需要做些什么

有关如何从Zsh中的多命令命令行获取最后一个命令的任何想法?

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

zsh
3个回答
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\'

如果你需要用双引号括起!#,但在这种情况下你必须从“最后一个命令”的末尾删除;: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之类的外部命令多播一些。


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语法。


0
投票

All you need is !! To repeat your last command

If you want to grab a specific part of that command

!!:0 Will grab the first character grouping (until it reaches a space delimiter)

!!:1 Will grab the second character grouping (until it reaches a space delimiter)

And so on...

© www.soinside.com 2019 - 2024. All rights reserved.