有没有办法在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中没有简单的方法。我相信在交互式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之类的外部命令多播一些。
试图回答我自己的问题。我仍然欢迎其他人的答案,因为这个答案并不完美。
至少,有一种方法可以使用$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语法。
!!
To repeat your last 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)