有没有办法在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中从多命令命令行获取最后一个命令?
当命令需要知道前一个命令是什么时,我需要它,无论该命令是在同一行还是前一行。另一种说法,可能是:我需要访问单个面向命令的历史记录的最后一项,而不是命令行的历史记录。
答案 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
将抓取第二个字符分组(直到到达空格分隔符)