我知道我可以使用 运行 bash 中的最后一个命令,!!
但是我如何运行最后一行输出?
我正在考虑这个输出的用例:
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git
但我不知道如何运行它。我在想类似的东西!!
,也许@@
或类似的东西?
答案1
该命令$(!! |& tail -1)
应该执行以下操作:
$ git something
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git
$ $(!! |& tail -1)
$(git something |& tail -1)
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
git-man liberror-perl
如您所见,sudo apt-get install git
命令正在运行。
编辑 :分解$(!! |& tail -1)
$()
是bash
命令替换模式bash
将扩展!!
到最后执行的命令|&
部分比较棘手。通常管道|
会将左侧命令的 STDOUT 作为 STDIN 传递给右侧命令|
,而在您的情况下,前一个命令会将其输出打印在 STDERR 上作为错误消息。因此,这样做|
没有帮助,我们需要将 STDOUT 和 STDERR(或仅 STDERR)都传递给右侧命令。|&
将把 STDOUT 和 STDERR 都作为 STDIN 传递给右侧命令。或者,最好只传递 STDERR:$(!! 2>&1 >/dev/null | tail -1)
tail -1
像往常一样将打印其输入的最后一行。在这里,您可以更精确地打印最后一行,例如打印包含以下命令的行apt-get install
:$(!! 2>&1 >/dev/null | grep 'apt-get install')
答案2
总结: alias @@='$($(fc -ln -1) |& tail -1)'
Bash 的历史记录交互功能不提供任何机制来检查输出命令。shell 不会存储该内容,历史扩展专门针对您自己运行的命令,或者这些命令的一部分。
剩下的方法是重新运行最后一个命令并通过管道传输标准输出和标准错误( |&
) 进入命令替换。heemayl 的回答实现了这一点,但不能在别名中使用,因为 shell 在扩展别名之前执行历史扩展,而不是之后。
我也无法让历史扩展在 shell 函数中工作,即使在函数中使用 启用它set -H
。我怀疑!!
函数中的扩展永远不会被扩展,而且我不确定如果扩展了它会扩展成什么样子,但现在我还不确定正是为什么事实并非如此。
因此,如果您想要进行设置以便只需很少的输入即可完成此操作,则应使用fc
shell 内置命令而不是使用历史扩展来从历史记录中提取最后一个命令。这还有一个好处,就是即使禁用了历史扩展,它也能正常工作。
如图所示戈登·戴维森的回答到创建包含 bash 历史扩展的别名(在超级用户),$(fc -ln -1)
模拟!!
。将其代!!
入heemayl 的命令 $(!! |& tail -1)
产量:
$($(fc -ln -1) |& tail -1)
其工作原理类似于$(!! |& tail -1)
但可以进入别名定义:
alias @@='$($(fc -ln -1) |& tail -1)'
运行该定义后,或者将其放入.bash_aliases
或.bashrc
启动新的 shell 后,您只需键入@@
(或任何您命名的别名)即可尝试执行最后一个命令的最后一行输出。
ek@Io:~$ alias @@='$($(fc -ln -1) |& tail -1)'
ek@Io:~$ evolution
The program 'evolution' is currently not installed. You can install it by typing:
sudo apt-get install evolution
ek@Io:~$ @@
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
evolution-common evolution-data-server evolution-data-server-online-accounts
....
答案3
如果您在 X 下使用终端仿真器,例如gnome-terminal
或konsole
,xterm
则可以使用 X 选择进行复制和粘贴等操作:
使用主要选择
选择全线运行左键单击三次。
然后将其粘贴到命令行用一个中键单击。
这应该适用于大多数终端仿真器。它利用了主选择,而不触及剪贴板 - 它们是分开的。
从技术上讲,它是选择,然后将复制和粘贴合并到一个操作中。
答案4
总结:您是否需要运行secondlast
最后一条命令的输出行:
alias @@='$($(fc -ln -1) |& tail -2 | head -1)'
在 Ubuntu 19.10 中,当找不到命令并sudo apt install
显示该命令时,下一个命令提示符之前会有一个空白行,因此使用时不会发生任何事情:alias @@='$($(fc -ln -1) |& tail -1)'
net@net:~$ pip install -e ".[uvloop]"
Command 'pip' not found, but can be installed with:
sudo apt install python-pip
net@net:~$ @@
net@net:~$
在这种情况下,您必须获取secondlast
最后一条命令的输出行:
alias @@='$($(fc -ln -1) |& tail -2 | head -1)'
net@net:~$ pip install -e ".[uvloop]"
Command 'pip' not found, but can be installed with:
sudo apt install python-pip
net@net:~$ @@
[sudo] password for net:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
...
...