Como posso executar a última linha de saída no bash?

9

Eu sei que posso executar o último comando no bash, com !! , mas como posso executar a última linha de saída?

Estou pensando no caso de uso dessa saída:

The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git

Mas eu não sei como posso executar isso. Estou pensando em algo parecido com o !! , talvez @@ ou similar?

Super-usuário também tem essa pergunta.

    
por Tim 09.05.2015 / 23:50

3 respostas

12

O comando $(!! |& tail -1) deve fazer:

$ 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

Como você pode ver, o comando sudo apt-get install git está sendo executado.

EDITAR: Desmembrando $(!! |& tail -1)

  • $() é o padrão de substituição do comando bash

  • bash expandirá !! para o último comando executado

  • |& part é complicado. Normalmente pipe | pegará o STDOUT do comando do lado esquerdo e passará como STDIN para o comando no lado direito do | , no seu caso o comando anterior imprime sua saída no STDERR como uma mensagem de erro. Então, fazer | não ajudaria, precisamos passar tanto o STDOUT quanto o STDERR (ou somente o STDERR) para o comando do lado direito. |& passará o STDOUT e o STDERR como o STDIN para o comando do lado direito. Alternativamente, melhor você só pode passar o STDERR:

    $(!! 2>&1 >/dev/null | tail -1)
    
  • tail -1 , como de costume, imprimirá a última linha de sua entrada. Aqui, em vez de imprimir a última linha, você pode ser mais preciso, como imprimir a linha que contém o comando apt-get install :

    $(!! 2>&1 >/dev/null | grep 'apt-get install')
    
por heemayl 10.05.2015 / 00:04
4

TL; DR: alias @@='$($(fc -ln -1) |& tail -1)'

As instalações de interação do histórico do Bash não oferecem nenhum mecanismo para examinar a saída dos comandos. O shell não armazena isso , e a expansão do histórico é especificamente para comandos que você mesmo executou, ou partes desses comandos.

Isso deixa a abordagem de executar novamente o último comando e canalizar os stdout e stderr ( |& ) em uma substituição de comando. A resposta do heemayl consegue isso, mas não pode ser usada em um alias porque o shell executa a expansão do histórico antes de expandir os aliases, e não depois .

Não consigo que a expansão do histórico funcione em uma função shell, mesmo ativando-a na função com set -H . Eu suspeito que !! em uma função nunca será expandida, e eu não tenho certeza do que seria expandido se fosse, mas agora eu não tenho certeza precisamente por que ela não é .

Portanto, se você quiser configurar as coisas para que possa fazer isso com muito pouca digitação, use o fc shell builtin em vez de expansão de histórico para extrair o último comando do histórico. Isso tem a vantagem adicional de funcionar mesmo quando a expansão de histórico está desativada.

Como mostrado em Gordon Davisson 's answer para Criando um alias contendo histórico bash expansão (em Super User ), $(fc -ln -1) simula !! . Conectando isso para !! no comando do heemayl $(!! |& tail -1) yields:

$($(fc -ln -1) |& tail -1)

Isso funciona como $(!! |& tail -1) , mas pode ser usado em uma definição de alias:

alias @@='$($(fc -ln -1) |& tail -1)'

Depois de executar essa definição, ou colocá-la em .bash_aliases ou .bashrc e iniciar um novo shell, você pode simplesmente digitar @@ (ou qualquer nome que tenha o alias) para tentar executar a última linha de saída do último comando.

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
....
    
por Eliah Kagan 10.05.2015 / 01:17
2

Se você estiver usando um emulador de terminal em X, como gnome-terminal , konsole ou xterm , você pode usar a seleção X para algo como copiar e colar:

Use a seleção principal

Selecione a linha inteira para executar com um triplo clique esquerdo .

Depois, cole-o na linha de comando usando um clique no botão do meio .

Isso deve funcionar na maioria dos emuladores de terminal. Faz uso da seleção principal, sem tocar na área de transferência - eles são separados.
É selecionar e, em seguida, combinar copiar e colar em uma operação, tecnicamente.

    
por Volker Siegel 10.05.2015 / 05:54

Tags